Update GPL boilerplate and (C)
[ardour.git] / gtk2_ardour / route_time_axis.cc
1 /*
2  * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
3  * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
4  * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2007 Doug McLain <doug@nostar.net>
6  * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
7  * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
8  * Copyright (C) 2013-2014 Colin Fletcher <colin.m.fletcher@googlemail.com>
9  * Copyright (C) 2014-2017 Ben Loftis <ben@harrisonconsoles.com>
10  * Copyright (C) 2015-2016 Nick Mainsbridge <mainsbridge@gmail.com>
11  * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
12  * Copyright (C) 2016 Julien "_FrnchFrgg_" RIVAUD <frnchfrgg@free.fr>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  */
28
29 #include <cstdlib>
30 #include <cmath>
31 #include <cassert>
32
33 #include <algorithm>
34 #include <string>
35 #include <vector>
36 #include <map>
37 #include <utility>
38
39 #include <sigc++/bind.h>
40
41 #include <gtkmm/menu.h>
42 #include <gtkmm/menuitem.h>
43 #include <gtkmm/stock.h>
44
45 #include "pbd/error.h"
46 #include "pbd/stl_delete.h"
47 #include "pbd/whitespace.h"
48 #include "pbd/memento_command.h"
49 #include "pbd/enumwriter.h"
50 #include "pbd/stateful_diff_command.h"
51
52 #include "evoral/Parameter.hpp"
53
54 #include "ardour/amp.h"
55 #include "ardour/meter.h"
56 #include "ardour/event_type_map.h"
57 #include "ardour/pannable.h"
58 #include "ardour/panner.h"
59 #include "ardour/plugin_insert.h"
60 #include "ardour/processor.h"
61 #include "ardour/profile.h"
62 #include "ardour/route_group.h"
63 #include "ardour/session.h"
64 #include "ardour/session_playlists.h"
65 #include "ardour/track.h"
66
67 #include "canvas/debug.h"
68
69 #include "gtkmm2ext/gtk_ui.h"
70 #include "gtkmm2ext/utils.h"
71
72 #include "widgets/ardour_button.h"
73 #include "widgets/prompter.h"
74 #include "widgets/tooltips.h"
75
76 #include "ardour_ui.h"
77 #include "audio_streamview.h"
78 #include "debug.h"
79 #include "enums_convert.h"
80 #include "route_time_axis.h"
81 #include "automation_time_axis.h"
82 #include "enums.h"
83 #include "gui_thread.h"
84 #include "item_counts.h"
85 #include "keyboard.h"
86 #include "paste_context.h"
87 #include "patch_change_widget.h"
88 #include "playlist_selector.h"
89 #include "point_selection.h"
90 #include "public_editor.h"
91 #include "region_view.h"
92 #include "rgb_macros.h"
93 #include "selection.h"
94 #include "streamview.h"
95 #include "ui_config.h"
96 #include "utils.h"
97 #include "route_group_menu.h"
98
99 #include "pbd/i18n.h"
100
101 using namespace ARDOUR;
102 using namespace ArdourWidgets;
103 using namespace PBD;
104 using namespace Gtkmm2ext;
105 using namespace Gtk;
106 using namespace Editing;
107 using namespace std;
108 using std::list;
109
110 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, ArdourCanvas::Canvas& canvas)
111         : RouteUI(sess)
112         , StripableTimeAxisView(ed, sess, canvas)
113         , _view (0)
114         , button_table (3, 3)
115         , route_group_button (S_("RTAV|G"))
116         , playlist_button (S_("RTAV|P"))
117         , automation_button (S_("RTAV|A"))
118         , automation_action_menu (0)
119         , plugins_submenu_item (0)
120         , route_group_menu (0)
121         , playlist_action_menu (0)
122         , gm (sess, true, 75, 14)
123         , _ignore_set_layer_display (false)
124         , pan_automation_item(NULL)
125 {
126         number_label.set_name("tracknumber label");
127         number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
128         number_label.set_alignment(.5, .5);
129         number_label.set_fallthrough_to_parent (true);
130
131         sess->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::parameter_changed, this, _1), gui_context());
132         UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::parameter_changed));
133
134         parameter_changed ("editor-stereo-only-meters");
135 }
136
137 void
138 RouteTimeAxisView::route_property_changed (const PBD::PropertyChange& what_changed)
139 {
140         if (what_changed.contains (ARDOUR::Properties::name)) {
141                 label_view ();
142         }
143 }
144
145 void
146 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
147 {
148         RouteUI::set_route (rt);
149         StripableTimeAxisView::set_stripable (rt);
150
151         CANVAS_DEBUG_NAME (_canvas_display, string_compose ("main for %1", rt->name()));
152         CANVAS_DEBUG_NAME (selection_group, string_compose ("selections for %1", rt->name()));
153         CANVAS_DEBUG_NAME (_ghost_group, string_compose ("ghosts for %1", rt->name()));
154
155         int meter_width = 3;
156         if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
157                 meter_width = 6;
158         }
159         gm.set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
160         gm.get_level_meter().set_no_show_all();
161         gm.get_level_meter().setup_meters(50, meter_width);
162         gm.update_gain_sensitive ();
163
164         uint32_t height;
165         if (get_gui_property ("height", height)) {
166                 set_height (height);
167         } else {
168                 set_height (preset_height (HeightNormal));
169         }
170
171         if (!_route->is_auditioner()) {
172                 if (gui_property ("visible").empty()) {
173                         set_gui_property ("visible", true);
174                 }
175         } else {
176                 set_gui_property ("visible", false);
177         }
178
179         timestretch_rect = 0;
180         no_redraw = false;
181
182         ignore_toggle = false;
183
184         route_group_button.set_name ("route button");
185         playlist_button.set_name ("route button");
186         automation_button.set_name ("route button");
187
188         route_group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
189         playlist_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click), false);
190         automation_button.signal_button_press_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click), false);
191
192         if (is_track()) {
193
194                 if (ARDOUR::Profile->get_mixbus()) {
195                         controls_table.attach (*rec_enable_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
196                 } else {
197                         controls_table.attach (*rec_enable_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
198                 }
199
200                 if (is_midi_track()) {
201                         set_tooltip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
202                         gm.set_fader_name ("MidiTrackFader");
203                 } else {
204                         set_tooltip(*rec_enable_button, _("Record"));
205                         gm.set_fader_name ("AudioTrackFader");
206                 }
207
208                 /* set playlist button tip to the current playlist, and make it update when it changes */
209                 update_playlist_tip ();
210                 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
211
212         } else {
213                 gm.set_fader_name ("AudioBusFader");
214                 Gtk::Fixed *blank = manage(new Gtk::Fixed());
215                 controls_button_size_group->add_widget(*blank);
216                 if (ARDOUR::Profile->get_mixbus() ) {
217                         controls_table.attach (*blank, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
218                 } else {
219                         controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
220                 }
221                 blank->show();
222         }
223
224         top_hbox.pack_end(gm.get_level_meter(), false, false, 2);
225
226         if (!ARDOUR::Profile->get_mixbus()) {
227                 controls_meters_size_group->add_widget (gm.get_level_meter());
228         }
229
230         if (_route->is_master()) {
231                 route_group_button.set_sensitive(false);
232         }
233
234         _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
235         _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
236         _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
237         _route->track_number_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::label_view, this), gui_context());
238
239         if (ARDOUR::Profile->get_mixbus()) {
240                 controls_table.attach (*mute_button, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
241         } else {
242                 controls_table.attach (*mute_button, 3, 4, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
243         }
244         // mute button is always present, it is used to
245         // force the 'blank' placeholders to the proper size
246         controls_button_size_group->add_widget(*mute_button);
247
248         if (!_route->is_master()) {
249                 if (ARDOUR::Profile->get_mixbus()) {
250                         controls_table.attach (*solo_button, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
251                 } else {
252                         controls_table.attach (*solo_button, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
253                 }
254         } else {
255                 Gtk::Fixed *blank = manage(new Gtk::Fixed());
256                 controls_button_size_group->add_widget(*blank);
257                 if (ARDOUR::Profile->get_mixbus()) {
258                         controls_table.attach (*blank, 2, 3, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
259                 } else {
260                         controls_table.attach (*blank, 4, 5, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
261                 }
262                 blank->show();
263         }
264
265         if (ARDOUR::Profile->get_mixbus()) {
266                 controls_table.attach (route_group_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
267                 controls_table.attach (gm.get_gain_slider(), 3, 5, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
268         }
269         else if (!ARDOUR::Profile->get_trx()) {
270                 controls_table.attach (route_group_button, 4, 5, 2, 3, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
271                 controls_table.attach (gm.get_gain_slider(), 0, 2, 2, 3, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 1, 0);
272         }
273
274         set_tooltip(*solo_button,_("Solo"));
275         set_tooltip(*mute_button,_("Mute"));
276         set_tooltip(route_group_button, _("Route Group"));
277
278         mute_button->set_tweaks(ArdourButton::TrackHeader);
279         solo_button->set_tweaks(ArdourButton::TrackHeader);
280         rec_enable_button->set_tweaks(ArdourButton::TrackHeader);
281         playlist_button.set_tweaks(ArdourButton::TrackHeader);
282         automation_button.set_tweaks(ArdourButton::TrackHeader);
283         route_group_button.set_tweaks(ArdourButton::TrackHeader);
284
285         if (is_midi_track()) {
286                 set_tooltip(automation_button, _("MIDI Controllers and Automation"));
287         } else {
288                 set_tooltip(automation_button, _("Automation"));
289         }
290
291         update_track_number_visibility();
292         label_view ();
293
294         if (ARDOUR::Profile->get_mixbus()) {
295                 controls_table.attach (automation_button, 1, 2, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
296         }
297         else if (!ARDOUR::Profile->get_trx()) {
298                 controls_table.attach (automation_button, 3, 4, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
299         }
300
301         if (is_track() && track()->mode() == ARDOUR::Normal) {
302                 if (ARDOUR::Profile->get_mixbus()) {
303                         controls_table.attach (playlist_button, 0, 1, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
304                 }
305                 else if (!ARDOUR::Profile->get_trx()) {
306                         controls_table.attach (playlist_button, 2, 3, 2, 3, Gtk::SHRINK, Gtk::SHRINK);
307                 }
308         }
309
310         _y_position = -1;
311
312         _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
313
314         if (is_track()) {
315
316                 LayerDisplay layer_display;
317                 if (get_gui_property ("layer-display", layer_display)) {
318                         set_layer_display (layer_display);
319                 }
320
321                 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
322                 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
323
324                 /* pick up the correct freeze state */
325                 map_frozen ();
326
327         }
328
329         UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
330
331         PropertyList* plist = new PropertyList();
332
333         plist->add (ARDOUR::Properties::group_mute, true);
334         plist->add (ARDOUR::Properties::group_solo, true);
335
336         route_group_menu = new RouteGroupMenu (_session, plist);
337
338         gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false);
339 }
340
341 RouteTimeAxisView::~RouteTimeAxisView ()
342 {
343         cleanup_gui_properties ();
344
345         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
346                 delete *i;
347         }
348
349         delete playlist_action_menu;
350         delete automation_action_menu;
351
352         delete _view;
353         _view = 0;
354
355         _automation_tracks.clear ();
356
357         delete route_group_menu;
358         CatchDeletion (this);
359 }
360
361 string
362 RouteTimeAxisView::name() const
363 {
364         if (_route) {
365                 return _route->name();
366         }
367         return string();
368 }
369
370 void
371 RouteTimeAxisView::post_construct ()
372 {
373         /* map current state of the route */
374
375         update_diskstream_display ();
376         setup_processor_menu_and_curves ();
377         reset_processor_automation_curves ();
378 }
379
380 /** Set up the processor menu for the current set of processors, and
381  *  display automation curves for any parameters which have data.
382  */
383 void
384 RouteTimeAxisView::setup_processor_menu_and_curves ()
385 {
386         _subplugin_menu_map.clear ();
387         subplugin_menu.items().clear ();
388         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
389         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
390 }
391
392 bool
393 RouteTimeAxisView::route_group_click (GdkEventButton *ev)
394 {
395         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
396                 if (_route->route_group()) {
397                         _route->route_group()->remove (_route);
398                 }
399                 return false;
400         }
401
402         WeakRouteList r;
403         r.push_back (route ());
404
405         route_group_menu->build (r);
406         if (ev->button == 1) {
407                 Gtkmm2ext::anchored_menu_popup(route_group_menu->menu(),
408                                                &route_group_button,
409                                                "", 1, ev->time);
410         } else {
411                 route_group_menu->menu()->popup (ev->button, ev->time);
412         }
413
414         return true;
415 }
416
417 void
418 RouteTimeAxisView::playlist_changed ()
419 {
420         label_view ();
421 }
422
423 void
424 RouteTimeAxisView::label_view ()
425 {
426         string x = _route->name ();
427         if (x != name_label.get_text ()) {
428                 name_label.set_text (x);
429         }
430         const int64_t track_number = _route->track_number ();
431         if (track_number == 0) {
432                 number_label.set_text ("");
433         } else {
434                 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
435         }
436 }
437
438 void
439 RouteTimeAxisView::update_track_number_visibility ()
440 {
441         DisplaySuspender ds;
442         bool show_label = _session->config.get_track_name_number();
443
444         if (_route && _route->is_master()) {
445                 show_label = false;
446         }
447
448         if (number_label.get_parent()) {
449                 controls_table.remove (number_label);
450         }
451         if (show_label) {
452                 if (ARDOUR::Profile->get_mixbus()) {
453                         controls_table.attach (number_label, 3, 4, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
454                 } else {
455                         controls_table.attach (number_label, 0, 1, 0, 1, Gtk::SHRINK, Gtk::EXPAND|Gtk::FILL, 1, 0);
456                 }
457                 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
458                 // except the width of the number label is subtracted from the name-hbox, so we
459                 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
460                 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
461                 if (tnw & 1) --tnw;
462                 number_label.set_size_request(tnw, -1);
463                 number_label.show ();
464         } else {
465                 number_label.hide ();
466         }
467 }
468
469 void
470 RouteTimeAxisView::parameter_changed (string const & p)
471 {
472         if (p == "track-name-number") {
473                 update_track_number_visibility();
474         } else if (p == "editor-stereo-only-meters") {
475                 if (UIConfiguration::instance().get_editor_stereo_only_meters()) {
476                         gm.get_level_meter().set_max_audio_meter_count (2);
477                 } else {
478                         gm.get_level_meter().set_max_audio_meter_count (0);
479                 }
480         }
481 }
482
483 void
484 RouteTimeAxisView::take_name_changed (void *src)
485 {
486         if (src != this) {
487                 label_view ();
488         }
489 }
490
491 bool
492 RouteTimeAxisView::playlist_click (GdkEventButton *ev)
493 {
494         if (ev->button != 1) {
495                 return true;
496         }
497
498         build_playlist_menu ();
499         conditionally_add_to_selection ();
500         Gtkmm2ext::anchored_menu_popup(playlist_action_menu, &playlist_button,
501                                        "", 1, ev->time);
502         return true;
503 }
504
505 bool
506 RouteTimeAxisView::automation_click (GdkEventButton *ev)
507 {
508         if (ev->button != 1) {
509                 return true;
510         }
511
512         conditionally_add_to_selection ();
513         build_automation_action_menu (false);
514         Gtkmm2ext::anchored_menu_popup(automation_action_menu, &automation_button,
515                                        "", 1, ev->time);
516         return true;
517 }
518
519 void
520 RouteTimeAxisView::build_automation_action_menu (bool for_selection)
521 {
522         using namespace Menu_Helpers;
523
524         /* detach subplugin_menu from automation_action_menu before we delete automation_action_menu,
525            otherwise bad things happen (see comment for similar case in MidiTimeAxisView::build_automation_action_menu)
526         */
527
528         detach_menu (subplugin_menu);
529
530         _main_automation_menu_map.clear ();
531         delete automation_action_menu;
532         automation_action_menu = new Menu;
533
534         MenuList& items = automation_action_menu->items();
535
536         automation_action_menu->set_name ("ArdourContextMenu");
537
538         items.push_back (MenuElem (_("Show All Automation"),
539                                    sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_all_automation), for_selection)));
540
541         items.push_back (MenuElem (_("Show Existing Automation"),
542                                    sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_existing_automation), for_selection)));
543
544         items.push_back (MenuElem (_("Hide All Automation"),
545                                    sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::hide_all_automation), for_selection)));
546
547         /* Attach the plugin submenu. It may have previously been used elsewhere,
548            so it was detached above
549         */
550
551         bool single_track_selected = (!for_selection || _editor.get_selection().tracks.size() == 1);
552
553         if (!subplugin_menu.items().empty()) {
554                 items.push_back (SeparatorElem ());
555                 items.push_back (MenuElem (_("Processor automation"), subplugin_menu));
556                 items.back().set_sensitive (single_track_selected);
557         }
558
559         /* Add any route automation */
560
561         if (gain_track) {
562                 items.push_back (CheckMenuElem (_("Fader"), sigc::mem_fun (*this, &RouteTimeAxisView::update_gain_track_visibility)));
563                 gain_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
564                 gain_automation_item->set_active (single_track_selected &&
565                                                   string_to<bool>(gain_track->gui_property ("visible")));
566
567                 _main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
568         }
569
570         if (trim_track) {
571                 items.push_back (CheckMenuElem (_("Trim"), sigc::mem_fun (*this, &RouteTimeAxisView::update_trim_track_visibility)));
572                 trim_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
573                 trim_automation_item->set_active (single_track_selected &&
574                                                   string_to<bool>(trim_track->gui_property ("visible")));
575
576                 _main_automation_menu_map[Evoral::Parameter(TrimAutomation)] = trim_automation_item;
577         }
578
579         if (mute_track) {
580                 items.push_back (CheckMenuElem (_("Mute"), sigc::mem_fun (*this, &RouteTimeAxisView::update_mute_track_visibility)));
581                 mute_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
582                 mute_automation_item->set_active (single_track_selected &&
583                                                   string_to<bool>(mute_track->gui_property ("visible")));
584
585                 _main_automation_menu_map[Evoral::Parameter(MuteAutomation)] = mute_automation_item;
586         }
587
588         if (!pan_tracks.empty() && !ARDOUR::Profile->get_mixbus()) {
589                 items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &RouteTimeAxisView::update_pan_track_visibility)));
590                 pan_automation_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
591                 pan_automation_item->set_active (single_track_selected &&
592                                                  string_to<bool>(pan_tracks.front()->gui_property ("visible")));
593
594                 set<Evoral::Parameter> const & params = _route->pannable()->what_can_be_automated ();
595                 for (set<Evoral::Parameter>::const_iterator p = params.begin(); p != params.end(); ++p) {
596                         _main_automation_menu_map[*p] = pan_automation_item;
597                 }
598         }
599 }
600
601 void
602 RouteTimeAxisView::build_display_menu ()
603 {
604         using namespace Menu_Helpers;
605
606         /* prepare it */
607
608         TimeAxisView::build_display_menu ();
609
610         /* now fill it with our stuff */
611
612         MenuList& items = display_menu->items();
613         display_menu->set_name ("ArdourContextMenu");
614
615         items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
616
617         items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
618
619         items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
620
621         items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
622
623         items.push_back (SeparatorElem());
624
625         if (_size_menu) {
626                 detach_menu (*_size_menu);
627         }
628         build_size_menu ();
629         items.push_back (MenuElem (_("Height"), *_size_menu));
630         items.push_back (SeparatorElem());
631
632         // Hook for derived classes to add type specific stuff
633         append_extra_display_menu_items ();
634
635         if (is_track()) {
636
637                 Menu* layers_menu = manage (new Menu);
638                 MenuList &layers_items = layers_menu->items();
639                 layers_menu->set_name("ArdourContextMenu");
640
641                 RadioMenuItem::Group layers_group;
642
643                 /* Find out how many overlaid/stacked tracks we have in the selection */
644
645                 int overlaid = 0;
646                 int stacked = 0;
647                 int unchangeable = 0;
648                 TrackSelection const & s = _editor.get_selection().tracks;
649
650                 for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
651                         StreamView* v = (*i)->view ();
652                         if (!v) {
653                                 continue;
654                         }
655
656                         if (v->can_change_layer_display()) {
657                                 switch (v->layer_display ()) {
658                                 case Overlaid:
659                                         ++overlaid;
660                                         break;
661                                 case Stacked:
662                                 case Expanded:
663                                         ++stacked;
664                                         break;
665                                 }
666                         } else {
667                                 unchangeable++;
668                         }
669                 }
670
671                 /* We're not connecting to signal_toggled() here; in the case where these two items are
672                    set to be in the `inconsistent' state, it seems that one or other will end up active
673                    as well as inconsistent (presumably due to the RadioMenuItem::Group).  Then when you
674                    select the active one, no toggled signal is emitted so nothing happens.
675                 */
676
677                 _ignore_set_layer_display = true;
678
679                 layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
680                 RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
681                 i->set_active (overlaid != 0 && stacked == 0);
682                 i->set_inconsistent (overlaid != 0 && stacked != 0);
683                 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
684
685                 if (unchangeable) {
686                         i->set_sensitive (false);
687                 }
688
689                 layers_items.push_back (RadioMenuElem (layers_group, _("Stacked")));
690                 i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
691                 i->set_active (overlaid == 0 && stacked != 0);
692                 i->set_inconsistent (overlaid != 0 && stacked != 0);
693                 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
694
695                 if (unchangeable) {
696                         i->set_sensitive (false);
697                 }
698
699                 _ignore_set_layer_display = false;
700
701                 items.push_back (MenuElem (_("Layers"), *layers_menu));
702
703                 Menu* alignment_menu = manage (new Menu);
704                 MenuList& alignment_items = alignment_menu->items();
705                 alignment_menu->set_name ("ArdourContextMenu");
706
707                 RadioMenuItem::Group align_group;
708
709                 /* Same verbose hacks as for the layering options above */
710
711                 int existing = 0;
712                 int capture = 0;
713                 int automatic = 0;
714                 int styles = 0;
715                 boost::shared_ptr<Track> first_track;
716
717                 for (TrackSelection::const_iterator t = s.begin(); t != s.end(); ++t) {
718                         RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*t);
719                         if (!r || !r->is_track ()) {
720                                 continue;
721                         }
722
723                         if (!first_track) {
724                                 first_track = r->track();
725                         }
726
727                         switch (r->track()->alignment_choice()) {
728                         case Automatic:
729                                 ++automatic;
730                                 styles |= 0x1;
731                                 switch (r->track()->alignment_style()) {
732                                 case ExistingMaterial:
733                                         ++existing;
734                                         break;
735                                 case CaptureTime:
736                                         ++capture;
737                                         break;
738                                 }
739                                 break;
740                         case UseExistingMaterial:
741                                 ++existing;
742                                 styles |= 0x2;
743                                 break;
744                         case UseCaptureTime:
745                                 ++capture;
746                                 styles |= 0x4;
747                                 break;
748                         }
749                 }
750
751                 bool inconsistent;
752                 switch (styles) {
753                 case 1:
754                 case 2:
755                 case 4:
756                         inconsistent = false;
757                         break;
758                 default:
759                         inconsistent = true;
760                         break;
761                 }
762
763                 if (!inconsistent && first_track) {
764
765                         alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
766                         i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
767                         i->set_active (automatic != 0 && existing == 0 && capture == 0);
768                         i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
769
770                         switch (first_track->alignment_choice()) {
771                         case Automatic:
772                                 switch (first_track->alignment_style()) {
773                                 case ExistingMaterial:
774                                         alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
775                                         break;
776                                 case CaptureTime:
777                                         alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
778                                         break;
779                                 }
780                                 break;
781                         default:
782                                 break;
783                         }
784
785                         alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
786                         i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
787                         i->set_active (existing != 0 && capture == 0 && automatic == 0);
788                         i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
789
790                         alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
791                         i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
792                         i->set_active (existing == 0 && capture != 0 && automatic == 0);
793                         i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
794
795                         items.push_back (MenuElem (_("Alignment"), *alignment_menu));
796
797                 } else {
798                         /* show nothing */
799                         delete alignment_menu;
800                 }
801
802                 items.push_back (SeparatorElem());
803
804                 build_playlist_menu ();
805                 items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
806                 items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
807         }
808
809         if (!is_midi_track () && _route->the_instrument ()) {
810                 /* MIDI Bus */
811                 items.push_back (MenuElem (_("Patch Selector..."),
812                                         sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
813                 items.push_back (SeparatorElem());
814         }
815
816         route_group_menu->detach ();
817
818         WeakRouteList r;
819         for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
820                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
821                 if (rtv) {
822                         r.push_back (rtv->route ());
823                 }
824         }
825
826         if (r.empty ()) {
827                 r.push_back (route ());
828         }
829
830         if (!_route->is_master()) {
831                 route_group_menu->build (r);
832                 items.push_back (MenuElem (_("Group"), *route_group_menu->menu ()));
833         }
834
835         build_automation_action_menu (true);
836         items.push_back (MenuElem (_("Automation"), *automation_action_menu));
837
838         items.push_back (SeparatorElem());
839
840         int active = 0;
841         int inactive = 0;
842         TrackSelection const & s = _editor.get_selection().tracks;
843         for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
844                 RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
845                 if (!r) {
846                         continue;
847                 }
848
849                 if (r->route()->active()) {
850                         ++active;
851                 } else {
852                         ++inactive;
853                 }
854         }
855
856         items.push_back (CheckMenuElem (_("Active")));
857         Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
858         bool click_sets_active = true;
859         if (active > 0 && inactive == 0) {
860                 i->set_active (true);
861                 click_sets_active = false;
862         } else if (active > 0 && inactive > 0) {
863                 i->set_inconsistent (true);
864         }
865         i->set_sensitive(! _session->transport_rolling());
866         i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
867
868         items.push_back (SeparatorElem());
869         items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
870         if (_route && !_route->is_master()) {
871                 items.push_back (SeparatorElem());
872                 items.push_back (MenuElem (_("Duplicate..."), boost::bind (&ARDOUR_UI::start_duplicate_routes, ARDOUR_UI::instance())));
873         }
874         items.push_back (SeparatorElem());
875         items.push_back (MenuElem (_("Remove"), sigc::mem_fun(_editor, &PublicEditor::remove_tracks)));
876 }
877
878 void
879 RouteTimeAxisView::show_timestretch (samplepos_t start, samplepos_t end, int layers, int layer)
880 {
881         TimeAxisView::show_timestretch (start, end, layers, layer);
882
883         hide_timestretch ();
884
885 #if 0
886         if (ts.empty()) {
887                 return;
888         }
889
890
891         /* check that the time selection was made in our route, or our route group.
892            remember that route_group() == 0 implies the route is *not* in a edit group.
893         */
894
895         if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
896                 /* this doesn't apply to us */
897                 return;
898         }
899
900         /* ignore it if our edit group is not active */
901
902         if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
903                 return;
904         }
905 #endif
906
907         if (timestretch_rect == 0) {
908                 timestretch_rect = new ArdourCanvas::Rectangle (canvas_display ());
909                 timestretch_rect->set_fill_color (Gtkmm2ext::HSV (UIConfiguration::instance().color ("time stretch fill")).mod (UIConfiguration::instance().modifier ("time stretch fill")).color());
910                 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
911         }
912
913         timestretch_rect->show ();
914         timestretch_rect->raise_to_top ();
915
916         double const x1 = start / _editor.get_current_zoom();
917         double const x2 = (end - 1) / _editor.get_current_zoom();
918
919         timestretch_rect->set (ArdourCanvas::Rect (x1, current_height() * (layers - layer - 1) / layers,
920                                                    x2, current_height() * (layers - layer) / layers));
921 }
922
923 void
924 RouteTimeAxisView::hide_timestretch ()
925 {
926         TimeAxisView::hide_timestretch ();
927
928         if (timestretch_rect) {
929                 timestretch_rect->hide ();
930         }
931 }
932
933 void
934 RouteTimeAxisView::show_selection (TimeSelection& ts)
935 {
936
937 #if 0
938         /* ignore it if our edit group is not active or if the selection was started
939            in some other track or route group (remember that route_group() == 0 means
940            that the track is not in an route group).
941         */
942
943         if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
944             (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
945                 hide_selection ();
946                 return;
947         }
948 #endif
949
950         TimeAxisView::show_selection (ts);
951 }
952
953 void
954 RouteTimeAxisView::set_height (uint32_t h, TrackHeightMode m)
955 {
956         int gmlen = h - 9;
957         bool height_changed = (height == 0) || (h != height);
958
959         int meter_width = 3;
960         if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
961                 meter_width = 6;
962         }
963         gm.get_level_meter().setup_meters (gmlen, meter_width);
964
965         TimeAxisView::set_height (h, m);
966
967         if (_view) {
968                 _view->set_height ((double) current_height());
969         }
970
971         if (height >= preset_height (HeightNormal)) {
972
973                 reset_meter();
974
975                 gm.get_gain_slider().show();
976                 mute_button->show();
977                 if (!_route || _route->is_monitor()) {
978                         solo_button->hide();
979                 } else {
980                         solo_button->show();
981                 }
982                 if (rec_enable_button)
983                         rec_enable_button->show();
984
985                 route_group_button.show();
986                 automation_button.show();
987
988                 if (is_track() && track()->mode() == ARDOUR::Normal) {
989                         playlist_button.show();
990                 }
991
992         } else {
993
994                 reset_meter();
995
996                 gm.get_gain_slider().hide();
997                 mute_button->show();
998                 if (!_route || _route->is_monitor()) {
999                         solo_button->hide();
1000                 } else {
1001                         solo_button->show();
1002                 }
1003                 if (rec_enable_button)
1004                         rec_enable_button->show();
1005
1006                 route_group_button.hide ();
1007                 automation_button.hide ();
1008
1009                 if (is_track() && track()->mode() == ARDOUR::Normal) {
1010                         playlist_button.hide ();
1011                 }
1012
1013         }
1014
1015         if (height_changed && !no_redraw) {
1016                 /* only emit the signal if the height really changed */
1017                 request_redraw ();
1018         }
1019 }
1020
1021 void
1022 RouteTimeAxisView::route_color_changed ()
1023 {
1024         using namespace ARDOUR_UI_UTILS;
1025         if (_view) {
1026                 _view->apply_color (color(), StreamView::RegionColor);
1027         }
1028         number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1029 }
1030
1031 void
1032 RouteTimeAxisView::set_samples_per_pixel (double fpp)
1033 {
1034         if (_view) {
1035                 _view->set_samples_per_pixel (fpp);
1036         }
1037
1038         StripableTimeAxisView::set_samples_per_pixel (fpp);
1039 }
1040
1041 void
1042 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
1043 {
1044         if (!mitem->get_active()) {
1045                 /* this is one of the two calls made when these radio menu items change status. this one
1046                          is for the item that became inactive, and we want to ignore it.
1047                          */
1048                 return;
1049         }
1050
1051         if (apply_to_selection) {
1052                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
1053         } else {
1054                 if (track ()) {
1055                         track()->set_align_choice (choice);
1056                 }
1057         }
1058 }
1059
1060 void
1061 RouteTimeAxisView::rename_current_playlist ()
1062 {
1063         Prompter prompter (true);
1064         string name;
1065
1066         boost::shared_ptr<Track> tr = track();
1067         if (!tr || tr->destructive()) {
1068                 return;
1069         }
1070
1071         boost::shared_ptr<Playlist> pl = tr->playlist();
1072         if (!pl) {
1073                 return;
1074         }
1075
1076         prompter.set_title (_("Rename Playlist"));
1077         prompter.set_prompt (_("New name for playlist:"));
1078         prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1079         prompter.set_initial_text (pl->name());
1080         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1081
1082         while (true) {
1083                 if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
1084                         break;
1085                 }
1086                 prompter.get_result (name);
1087                 if (name.length()) {
1088                         if (_session->playlists()->by_name (name)) {
1089                                 MessageDialog msg (_("Given playlist name is not unique."));
1090                                 msg.run ();
1091                                 prompter.set_initial_text (Playlist::bump_name (name, *_session));
1092                         } else {
1093                                 pl->set_name (name);
1094                                 break;
1095                         }
1096                 }
1097         }
1098 }
1099
1100 std::string
1101 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1102 {
1103         std::string ret (basename);
1104
1105         std::string const group_string = "." + route_group()->name() + ".";
1106
1107         // iterate through all playlists
1108         int maxnumber = 0;
1109         for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1110                 std::string tmp = (*i)->name();
1111
1112                 std::string::size_type idx = tmp.find(group_string);
1113                 // find those which belong to this group
1114                 if (idx != string::npos) {
1115                         tmp = tmp.substr(idx + group_string.length());
1116
1117                         // and find the largest current number
1118                         int x = atoi(tmp);
1119                         if (x > maxnumber) {
1120                                 maxnumber = x;
1121                         }
1122                 }
1123         }
1124
1125         maxnumber++;
1126
1127         char buf[32];
1128         snprintf (buf, sizeof(buf), "%d", maxnumber);
1129
1130         ret = this->name() + "." + route_group()->name () + "." + buf;
1131
1132         return ret;
1133 }
1134
1135 void
1136 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op, bool copy)
1137 {
1138         string name;
1139
1140         boost::shared_ptr<Track> tr = track ();
1141         if (!tr || tr->destructive()) {
1142                 return;
1143         }
1144
1145         boost::shared_ptr<const Playlist> pl = tr->playlist();
1146         if (!pl) {
1147                 return;
1148         }
1149
1150         name = pl->name();
1151
1152         if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1153                 name = resolve_new_group_playlist_name(name,playlists_before_op);
1154         }
1155
1156         while (_session->playlists()->by_name(name)) {
1157                 name = Playlist::bump_name (name, *_session);
1158         }
1159
1160         if (prompt) {
1161                 // TODO: The prompter "new" button should be de-activated if the user
1162                 // specifies a playlist name which already exists in the session.
1163
1164                 Prompter prompter (true);
1165
1166                 if (copy) {
1167                         prompter.set_title (_("New Copy Playlist"));
1168                         prompter.set_prompt (_("Name for playlist copy:"));
1169                 } else {
1170                         prompter.set_title (_("New Playlist"));
1171                         prompter.set_prompt (_("Name for new playlist:"));
1172                 }
1173                 prompter.set_initial_text (name);
1174                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1175                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1176                 prompter.show_all ();
1177
1178                 while (true) {
1179                         if (prompter.run () != Gtk::RESPONSE_ACCEPT) {
1180                                 return;
1181                         }
1182                         prompter.get_result (name);
1183                         if (name.length()) {
1184                                 if (_session->playlists()->by_name (name)) {
1185                                         MessageDialog msg (_("Given playlist name is not unique."));
1186                                         msg.run ();
1187                                         prompter.set_initial_text (Playlist::bump_name (name, *_session));
1188                                 } else {
1189                                         break;
1190                                 }
1191                         }
1192                 }
1193         }
1194
1195         if (name.length()) {
1196                 if (copy) {
1197                         tr->use_copy_playlist ();
1198                 } else {
1199                         tr->use_default_new_playlist ();
1200                 }
1201                 tr->playlist()->set_name (name);
1202         }
1203 }
1204
1205 void
1206 RouteTimeAxisView::clear_playlist ()
1207 {
1208         boost::shared_ptr<Track> tr = track ();
1209         if (!tr || tr->destructive()) {
1210                 return;
1211         }
1212
1213         boost::shared_ptr<Playlist> pl = tr->playlist();
1214         if (!pl) {
1215                 return;
1216         }
1217
1218         _editor.clear_playlist (pl);
1219 }
1220
1221 void
1222 RouteTimeAxisView::speed_changed ()
1223 {
1224         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_pixel, this));
1225 }
1226
1227 void
1228 RouteTimeAxisView::update_diskstream_display ()
1229 {
1230         if (!track()) {
1231                 return;
1232         }
1233
1234         map_frozen ();
1235 }
1236
1237 void
1238 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1239 {
1240         if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1241
1242                 /* special case: select/deselect all tracks */
1243
1244                 _editor.begin_reversible_selection_op (X_("Selection Click"));
1245
1246                 if (_editor.get_selection().selected (this)) {
1247                         _editor.get_selection().clear_tracks ();
1248                 } else {
1249                         _editor.select_all_tracks ();
1250                 }
1251
1252                 _editor.commit_reversible_selection_op ();
1253
1254                 return;
1255         }
1256
1257         _editor.begin_reversible_selection_op (X_("Selection Click"));
1258
1259         switch (ArdourKeyboard::selection_type (ev->state)) {
1260         case Selection::Toggle:
1261                 _editor.get_selection().toggle (this);
1262                 break;
1263
1264         case Selection::Set:
1265                 _editor.get_selection().set (this);
1266                 break;
1267
1268         case Selection::Extend:
1269                 _editor.extend_selection_to_track (*this);
1270                 break;
1271
1272         case Selection::Add:
1273                 _editor.get_selection().add (this);
1274                 break;
1275         }
1276
1277         _editor.commit_reversible_selection_op ();
1278
1279         _editor.set_selected_mixer_strip (*this);
1280 }
1281
1282 void
1283 RouteTimeAxisView::set_selected_points (PointSelection& points)
1284 {
1285         StripableTimeAxisView::set_selected_points (points);
1286         AudioStreamView* asv = dynamic_cast<AudioStreamView*>(_view);
1287         if (asv) {
1288                 asv->set_selected_points (points);
1289         }
1290 }
1291
1292 void
1293 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1294 {
1295         if (_view) {
1296                 _view->set_selected_regionviews (regions);
1297         }
1298 }
1299
1300 /** Add the selectable things that we have to a list.
1301  * @param results List to add things to.
1302  */
1303 void
1304 RouteTimeAxisView::get_selectables (samplepos_t start, samplepos_t end, double top, double bot, list<Selectable*>& results, bool within)
1305 {
1306         if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1307                 _view->get_selectables (start, end, top, bot, results, within);
1308         }
1309
1310         /* pick up visible automation tracks */
1311         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1312                 if (!(*i)->hidden()) {
1313                         (*i)->get_selectables (start, end, top, bot, results, within);
1314                 }
1315         }
1316 }
1317
1318 void
1319 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1320 {
1321         if (_view) {
1322                 _view->get_inverted_selectables (sel, results);
1323         }
1324         StripableTimeAxisView::get_inverted_selectables (sel, results);
1325 }
1326
1327 RouteGroup*
1328 RouteTimeAxisView::route_group () const
1329 {
1330         return _route->route_group();
1331 }
1332
1333 boost::shared_ptr<Playlist>
1334 RouteTimeAxisView::playlist () const
1335 {
1336         boost::shared_ptr<Track> tr;
1337
1338         if ((tr = track()) != 0) {
1339                 return tr->playlist();
1340         } else {
1341                 return boost::shared_ptr<Playlist> ();
1342         }
1343 }
1344
1345 bool
1346 RouteTimeAxisView::name_entry_changed (string const& str)
1347 {
1348         if (str == _route->name()) {
1349                 return true;
1350         }
1351
1352         string x = str;
1353
1354         strip_whitespace_edges (x);
1355
1356         if (x.empty()) {
1357                 return false;
1358         }
1359
1360         if (_session->route_name_internal (x)) {
1361                 ARDOUR_UI::instance()->popup_error (string_compose (_("The name \"%1\" is reserved for %2"), x, PROGRAM_NAME));
1362                 return false;
1363         } else if (RouteUI::verify_new_route_name (x)) {
1364                 _route->set_name (x);
1365                 return true;
1366         }
1367
1368         return false;
1369 }
1370
1371 boost::shared_ptr<Region>
1372 RouteTimeAxisView::find_next_region (samplepos_t pos, RegionPoint point, int32_t dir)
1373 {
1374         boost::shared_ptr<Playlist> pl = playlist ();
1375
1376         if (pl) {
1377                 return pl->find_next_region (pos, point, dir);
1378         }
1379
1380         return boost::shared_ptr<Region> ();
1381 }
1382
1383 samplepos_t
1384 RouteTimeAxisView::find_next_region_boundary (samplepos_t pos, int32_t dir)
1385 {
1386         boost::shared_ptr<Playlist> pl = playlist ();
1387
1388         if (pl) {
1389                 return pl->find_next_region_boundary (pos, dir);
1390         }
1391
1392         return -1;
1393 }
1394
1395 void
1396 RouteTimeAxisView::fade_range (TimeSelection& selection)
1397 {
1398         boost::shared_ptr<Playlist> what_we_got;
1399         boost::shared_ptr<Track> tr = track ();
1400         boost::shared_ptr<Playlist> playlist;
1401
1402         if (tr == 0) {
1403                 /* route is a bus, not a track */
1404                 return;
1405         }
1406
1407         playlist = tr->playlist();
1408
1409         TimeSelection time (selection);
1410
1411         playlist->clear_changes ();
1412         playlist->clear_owned_changes ();
1413
1414         playlist->fade_range (time);
1415
1416         vector<Command*> cmds;
1417         playlist->rdiff (cmds);
1418         _session->add_commands (cmds);
1419         _session->add_command (new StatefulDiffCommand (playlist));
1420
1421 }
1422
1423 void
1424 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1425 {
1426         boost::shared_ptr<Playlist> what_we_got;
1427         boost::shared_ptr<Track> tr = track ();
1428         boost::shared_ptr<Playlist> playlist;
1429
1430         if (tr == 0) {
1431                 /* route is a bus, not a track */
1432                 return;
1433         }
1434
1435         playlist = tr->playlist();
1436
1437         TimeSelection time (selection.time);
1438
1439         playlist->clear_changes ();
1440         playlist->clear_owned_changes ();
1441
1442         switch (op) {
1443         case Delete:
1444                 if (playlist->cut (time) != 0) {
1445                         if (Config->get_edit_mode() == Ripple) {
1446                                 playlist->ripple(time.start(), -time.length(), NULL);
1447                         }
1448                         // no need to exclude any regions from rippling here
1449
1450                         vector<Command*> cmds;
1451                         playlist->rdiff (cmds);
1452                         _session->add_commands (cmds);
1453
1454                         _session->add_command (new StatefulDiffCommand (playlist));
1455                 }
1456                 break;
1457
1458         case Cut:
1459                 if ((what_we_got = playlist->cut (time)) != 0) {
1460                         _editor.get_cut_buffer().add (what_we_got);
1461                         if (Config->get_edit_mode() == Ripple) {
1462                                 playlist->ripple(time.start(), -time.length(), NULL);
1463                         }
1464                         // no need to exclude any regions from rippling here
1465
1466                         vector<Command*> cmds;
1467                         playlist->rdiff (cmds);
1468                         _session->add_commands (cmds);
1469
1470                         _session->add_command (new StatefulDiffCommand (playlist));
1471                 }
1472                 break;
1473         case Copy:
1474                 if ((what_we_got = playlist->copy (time)) != 0) {
1475                         _editor.get_cut_buffer().add (what_we_got);
1476                 }
1477                 break;
1478
1479         case Clear:
1480                 if ((what_we_got = playlist->cut (time)) != 0) {
1481                         if (Config->get_edit_mode() == Ripple) {
1482                                 playlist->ripple(time.start(), -time.length(), NULL);
1483                         }
1484                         // no need to exclude any regions from rippling here
1485
1486                         vector<Command*> cmds;
1487                         playlist->rdiff (cmds);
1488                         _session->add_commands (cmds);
1489                         _session->add_command (new StatefulDiffCommand (playlist));
1490                         what_we_got->release ();
1491                 }
1492                 break;
1493         }
1494 }
1495
1496 bool
1497 RouteTimeAxisView::paste (samplepos_t pos, const Selection& selection, PasteContext& ctx, const int32_t sub_num)
1498 {
1499         if (!is_track()) {
1500                 return false;
1501         }
1502
1503         boost::shared_ptr<Playlist>       pl   = playlist ();
1504         const ARDOUR::DataType            type = pl->data_type();
1505         PlaylistSelection::const_iterator p    = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
1506
1507         if (p == selection.playlists.end()) {
1508                 return false;
1509         }
1510         ctx.counts.increase_n_playlists(type);
1511
1512         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1513
1514         /* add multi-paste offset if applicable */
1515         std::pair<samplepos_t, samplepos_t> extent  = (*p)->get_extent();
1516         const samplecnt_t                  duration = extent.second - extent.first;
1517         pos += _editor.get_paste_offset(pos, ctx.count, duration);
1518
1519         pl->clear_changes ();
1520         pl->clear_owned_changes ();
1521         if (Config->get_edit_mode() == Ripple) {
1522                 std::pair<samplepos_t, samplepos_t> extent = (*p)->get_extent_with_endspace();
1523                 samplecnt_t amount = extent.second - extent.first;
1524                 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1525         }
1526         pl->paste (*p, pos, ctx.times, sub_num);
1527
1528         vector<Command*> cmds;
1529         pl->rdiff (cmds);
1530         _session->add_commands (cmds);
1531
1532         _session->add_command (new StatefulDiffCommand (pl));
1533
1534         return true;
1535 }
1536
1537
1538 struct PlaylistSorter {
1539         bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1540                 return a->sort_id() < b->sort_id();
1541         }
1542 };
1543
1544 void
1545 RouteTimeAxisView::build_playlist_menu ()
1546 {
1547         using namespace Menu_Helpers;
1548
1549         if (!is_track()) {
1550                 return;
1551         }
1552
1553         delete playlist_action_menu;
1554         playlist_action_menu = new Menu;
1555         playlist_action_menu->set_name ("ArdourContextMenu");
1556
1557         MenuList& playlist_items = playlist_action_menu->items();
1558         playlist_action_menu->set_name ("ArdourContextMenu");
1559         playlist_items.clear();
1560
1561         RadioMenuItem::Group playlist_group;
1562         boost::shared_ptr<Track> tr = track ();
1563
1564         vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists()->playlists_for_track (tr);
1565
1566         /* sort the playlists */
1567         PlaylistSorter cmp;
1568         sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1569
1570         /* add the playlists to the menu */
1571         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1572                 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1573                 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1574                 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1575
1576                 if (tr->playlist()->id() == (*i)->id()) {
1577                         item->set_active();
1578                 }
1579         }
1580
1581         playlist_items.push_back (SeparatorElem());
1582         playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1583         playlist_items.push_back (SeparatorElem());
1584
1585         if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1586                 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1587                 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1588
1589         } else {
1590                 // Use a label which tells the user what is happening
1591                 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1592                 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1593
1594         }
1595
1596         playlist_items.push_back (SeparatorElem());
1597         playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1598         playlist_items.push_back (SeparatorElem());
1599
1600         playlist_items.push_back (MenuElem(_("Select from All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1601 }
1602
1603 void
1604 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1605 {
1606         assert (is_track());
1607
1608         // exit if we were triggered by deactivating the old playlist
1609         if (!item->get_active()) {
1610                 return;
1611         }
1612
1613         boost::shared_ptr<Playlist> pl (wpl.lock());
1614
1615         if (!pl) {
1616                 return;
1617         }
1618
1619         if (track()->playlist() == pl) {
1620                 // exit when use_playlist is called by the creation of the playlist menu
1621                 // or the playlist choice is unchanged
1622                 return;
1623         }
1624
1625         track()->use_playlist (track()->data_type(), pl);
1626
1627         RouteGroup* rg = route_group();
1628
1629         if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1630                 std::string group_string = "." + rg->name() + ".";
1631
1632                 std::string take_name = pl->name();
1633                 std::string::size_type idx = take_name.find(group_string);
1634
1635                 if (idx == std::string::npos)
1636                         return;
1637
1638                 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1639
1640                 boost::shared_ptr<RouteList> rl (rg->route_list());
1641
1642                 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1643                         if ((*i) == this->route()) {
1644                                 continue;
1645                         }
1646
1647                         std::string playlist_name = (*i)->name()+group_string+take_name;
1648
1649                         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1650                         if (!track) {
1651                                 continue;
1652                         }
1653
1654                         if (track->freeze_state() == Track::Frozen) {
1655                                 /* Don't change playlists of frozen tracks */
1656                                 continue;
1657                         }
1658
1659                         boost::shared_ptr<Playlist> ipl = session()->playlists()->by_name(playlist_name);
1660                         if (!ipl) {
1661                                 // No playlist for this track for this take yet, make it
1662                                 track->use_default_new_playlist();
1663                                 track->playlist()->set_name(playlist_name);
1664                         } else {
1665                                 track->use_playlist(track->data_type(), ipl);
1666                         }
1667                 }
1668         }
1669 }
1670
1671 void
1672 RouteTimeAxisView::update_playlist_tip ()
1673 {
1674         RouteGroup* rg = route_group ();
1675         if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::group_select.property_id)) {
1676                 string group_string = "." + rg->name() + ".";
1677
1678                 string take_name = track()->playlist()->name();
1679                 string::size_type idx = take_name.find(group_string);
1680
1681                 if (idx != string::npos) {
1682                         /* find the bit containing the take number / name */
1683                         take_name = take_name.substr (idx + group_string.length());
1684
1685                         /* set the playlist button tooltip to the take name */
1686                         set_tooltip (
1687                                 playlist_button,
1688                                 string_compose(_("Take: %1.%2"),
1689                                         Gtkmm2ext::markup_escape_text (rg->name()),
1690                                         Gtkmm2ext::markup_escape_text (take_name))
1691                                 );
1692
1693                         return;
1694                 }
1695         }
1696
1697         /* set the playlist button tooltip to the playlist name */
1698         set_tooltip (playlist_button, _("Playlist") + std::string(": ") + Gtkmm2ext::markup_escape_text (track()->playlist()->name()));
1699 }
1700
1701
1702 void
1703 RouteTimeAxisView::show_playlist_selector ()
1704 {
1705         _editor.playlist_selector().show_for (this);
1706 }
1707
1708 void
1709 RouteTimeAxisView::map_frozen ()
1710 {
1711         if (!is_track()) {
1712                 return;
1713         }
1714
1715         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1716
1717         switch (track()->freeze_state()) {
1718         case Track::Frozen:
1719                 playlist_button.set_sensitive (false);
1720                 break;
1721         default:
1722                 playlist_button.set_sensitive (true);
1723                 break;
1724         }
1725         RouteUI::map_frozen ();
1726 }
1727
1728 void
1729 RouteTimeAxisView::color_handler ()
1730 {
1731         //case cTimeStretchOutline:
1732         if (timestretch_rect) {
1733                 timestretch_rect->set_outline_color (UIConfiguration::instance().color ("time stretch outline"));
1734         }
1735         //case cTimeStretchFill:
1736         if (timestretch_rect) {
1737                 timestretch_rect->set_fill_color (UIConfiguration::instance().color ("time stretch fill"));
1738         }
1739
1740         reset_meter();
1741 }
1742
1743 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1744  *  Will add track if necessary.
1745  */
1746 void
1747 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1748 {
1749         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1750         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1751
1752         if (!track) {
1753                 /* it doesn't exist yet, so we don't care about the button state: just add it */
1754                 create_automation_child (param, true);
1755         } else {
1756                 assert (menu);
1757                 bool yn = menu->get_active();
1758                 bool changed = false;
1759
1760                 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1761
1762                         /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1763                            will have done that for us.
1764                         */
1765
1766                         if (changed && !no_redraw) {
1767                                 request_redraw ();
1768                         }
1769                 }
1770         }
1771 }
1772
1773 void
1774 RouteTimeAxisView::update_pan_track_visibility ()
1775 {
1776         bool const showit = pan_automation_item->get_active();
1777         bool changed = false;
1778
1779         for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1780                 if ((*i)->set_marked_for_display (showit)) {
1781                         changed = true;
1782                 }
1783         }
1784
1785         if (changed) {
1786                 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1787         }
1788 }
1789
1790 void
1791 RouteTimeAxisView::ensure_pan_views (bool show)
1792 {
1793         bool changed = false;
1794         for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1795                 changed = true;
1796                 (*i)->set_marked_for_display (false);
1797         }
1798         if (changed) {
1799                 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1800         }
1801         pan_tracks.clear();
1802
1803         if (!_route->panner()) {
1804                 return;
1805         }
1806
1807         set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1808         set<Evoral::Parameter>::iterator p;
1809
1810         for (p = params.begin(); p != params.end(); ++p) {
1811                 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1812
1813                 if (pan_control->parameter().type() == NullAutomation) {
1814                         error << "Pan control has NULL automation type!" << endmsg;
1815                         continue;
1816                 }
1817
1818                 if (automation_child (pan_control->parameter ()).get () == 0) {
1819
1820                         /* we don't already have an AutomationTimeAxisView for this parameter */
1821
1822                         std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1823
1824                         boost::shared_ptr<AutomationTimeAxisView> t (
1825                                         new AutomationTimeAxisView (_session,
1826                                                 _route,
1827                                                 _route->pannable(),
1828                                                 pan_control,
1829                                                 pan_control->parameter (),
1830                                                 _editor,
1831                                                 *this,
1832                                                 false,
1833                                                 parent_canvas,
1834                                                 name)
1835                                         );
1836
1837                         pan_tracks.push_back (t);
1838                         add_automation_child (*p, t, show);
1839                 } else {
1840                         pan_tracks.push_back (automation_child (pan_control->parameter ()));
1841                 }
1842         }
1843 }
1844
1845
1846 void
1847 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
1848 {
1849         if (apply_to_selection) {
1850                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
1851         } else {
1852                 no_redraw = true;
1853
1854                 StripableTimeAxisView::show_all_automation ();
1855
1856                 /* Show processor automation */
1857
1858                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1859                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1860                                 if ((*ii)->view == 0) {
1861                                         add_processor_automation_curve ((*i)->processor, (*ii)->what);
1862                                 }
1863
1864                                 (*ii)->menu_item->set_active (true);
1865                         }
1866                 }
1867
1868                 no_redraw = false;
1869
1870                 /* Redraw */
1871
1872                 request_redraw ();
1873         }
1874 }
1875
1876 void
1877 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
1878 {
1879         if (apply_to_selection) {
1880                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
1881         } else {
1882                 no_redraw = true;
1883
1884                 StripableTimeAxisView::show_existing_automation ();
1885
1886                 /* Show processor automation */
1887                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1888                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1889                                 if ((*i)->processor->control((*ii)->what)->list()->size() > 0) {
1890                                         (*ii)->menu_item->set_active (true);
1891                                 }
1892                         }
1893                 }
1894
1895                 no_redraw = false;
1896                 request_redraw ();
1897         }
1898 }
1899
1900 void
1901 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
1902 {
1903         if (apply_to_selection) {
1904                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
1905         } else {
1906                 no_redraw = true;
1907                 StripableTimeAxisView::hide_all_automation ();
1908
1909                 /* Hide processor automation */
1910                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1911                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1912                                 (*ii)->menu_item->set_active (false);
1913                         }
1914                 }
1915
1916                 no_redraw = false;
1917                 request_redraw ();
1918         }
1919 }
1920
1921 void
1922 RouteTimeAxisView::region_view_added (RegionView* rv)
1923 {
1924         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
1925         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1926                 boost::shared_ptr<AutomationTimeAxisView> atv;
1927
1928                 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1929                         atv->add_ghost(rv);
1930                 }
1931         }
1932
1933         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
1934                 (*i)->add_ghost(rv);
1935         }
1936 }
1937
1938 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1939 {
1940         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1941                 delete *i;
1942         }
1943 }
1944
1945
1946 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1947 {
1948         parent.remove_processor_automation_node (this);
1949 }
1950
1951 void
1952 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1953 {
1954         if (pan->view) {
1955                 remove_child (pan->view);
1956         }
1957 }
1958
1959 RouteTimeAxisView::ProcessorAutomationNode*
1960 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1961 {
1962         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1963
1964                 if ((*i)->processor == processor) {
1965
1966                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1967                                 if ((*ii)->what == what) {
1968                                         return *ii;
1969                                 }
1970                         }
1971                 }
1972         }
1973
1974         return 0;
1975 }
1976
1977 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
1978 void
1979 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1980 {
1981         string name;
1982         ProcessorAutomationNode* pan;
1983
1984         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1985                 /* session state may never have been saved with new plugin */
1986                 error << _("programming error: ")
1987                       << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
1988                                          processor->name(), what.type(), (int) what.channel(), what.id() )
1989                       << endmsg;
1990                 abort(); /*NOTREACHED*/
1991                 return;
1992         }
1993
1994         if (pan->view) {
1995                 return;
1996         }
1997
1998         boost::shared_ptr<AutomationControl> control
1999                 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2000
2001         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2002                 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2003                                             _editor, *this, false, parent_canvas,
2004                                             processor->describe_parameter (what), processor->name()));
2005
2006         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2007
2008         add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2009
2010         if (_view) {
2011                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2012         }
2013 }
2014
2015 void
2016 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2017 {
2018         if (!_hidden) {
2019                 pan->menu_item->set_active (false);
2020         }
2021
2022         if (!no_redraw) {
2023                 request_redraw ();
2024         }
2025 }
2026
2027 void
2028 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2029 {
2030         boost::shared_ptr<Processor> processor (p.lock ());
2031
2032         if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2033                 /* The Amp processor is a special case and is dealt with separately */
2034                 return;
2035         }
2036
2037         set<Evoral::Parameter> existing;
2038
2039         processor->what_has_data (existing);
2040
2041         for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2042
2043                 Evoral::Parameter param (*i);
2044                 boost::shared_ptr<AutomationLine> al;
2045
2046                 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2047 #warning NOT REACHED -- bug?
2048                         al->queue_reset ();
2049                 } else {
2050                         add_processor_automation_curve (processor, param);
2051                 }
2052         }
2053 }
2054
2055 void
2056 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2057 {
2058         boost::shared_ptr<Processor> processor (p.lock ());
2059
2060         if (!processor || !processor->display_to_user ()) {
2061                 return;
2062         }
2063
2064         /* we use this override to veto the Amp processor from the plugin menu,
2065            as its automation lane can be accessed using the special "Fader" menu
2066            option
2067         */
2068
2069         if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2070                 return;
2071         }
2072
2073         using namespace Menu_Helpers;
2074         ProcessorAutomationInfo *rai;
2075         list<ProcessorAutomationInfo*>::iterator x;
2076
2077         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2078
2079         if (automatable.empty()) {
2080                 return;
2081         }
2082
2083         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2084                 if ((*x)->processor == processor) {
2085                         break;
2086                 }
2087         }
2088
2089         if (x == processor_automation.end()) {
2090                 rai = new ProcessorAutomationInfo (processor);
2091                 processor_automation.push_back (rai);
2092         } else {
2093                 rai = *x;
2094         }
2095
2096         /* any older menu was deleted at the top of processors_changed()
2097            when we cleared the subplugin menu.
2098         */
2099
2100         rai->menu = manage (new Menu);
2101         MenuList& items = rai->menu->items();
2102         rai->menu->set_name ("ArdourContextMenu");
2103
2104         items.clear ();
2105
2106         std::set<Evoral::Parameter> has_visible_automation;
2107         AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2108
2109         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2110
2111                 ProcessorAutomationNode* pan;
2112                 Gtk::CheckMenuItem* mitem;
2113
2114                 string name = processor->describe_parameter (*i);
2115
2116                 if (name == X_("hidden")) {
2117                         continue;
2118                 }
2119
2120                 items.push_back (CheckMenuElem (name));
2121                 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2122
2123                 _subplugin_menu_map[*i] = mitem;
2124
2125                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2126                         mitem->set_active(true);
2127                 }
2128
2129                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2130
2131                         /* new item */
2132
2133                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2134
2135                         rai->lines.push_back (pan);
2136
2137                 } else {
2138
2139                         pan->menu_item = mitem;
2140
2141                 }
2142
2143                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2144         }
2145
2146         if (items.size() == 0) {
2147                 return;
2148         }
2149
2150         /* add the menu for this processor, because the subplugin
2151            menu is always cleared at the top of processors_changed().
2152            this is the result of some poor design in gtkmm and/or
2153            GTK+.
2154         */
2155
2156         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2157         rai->valid = true;
2158 }
2159
2160 void
2161 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2162                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2163 {
2164         bool showit = pan->menu_item->get_active();
2165         bool redraw = false;
2166
2167         if (pan->view == 0 && showit) {
2168                 add_processor_automation_curve (rai->processor, pan->what);
2169                 redraw = true;
2170         }
2171
2172         if (pan->view && pan->view->set_marked_for_display (showit)) {
2173                 redraw = true;
2174         }
2175
2176         if (redraw && !no_redraw) {
2177                 request_redraw ();
2178         }
2179 }
2180
2181 void
2182 RouteTimeAxisView::reread_midnam ()
2183 {
2184         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (_route->the_instrument ());
2185         assert (pi);
2186         bool rv = pi->plugin ()->read_midnam();
2187
2188         if (rv && patch_change_dialog ()) {
2189                 patch_change_dialog ()->refresh ();
2190         }
2191 }
2192
2193 void
2194 RouteTimeAxisView::drop_instrument_ref ()
2195 {
2196         midnam_connection.drop_connections ();
2197 }
2198
2199 void
2200 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2201 {
2202         if (_route) {
2203                 boost::shared_ptr<Processor> the_instrument (_route->the_instrument());
2204                 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (the_instrument);
2205                 if (pi && pi->plugin ()->has_midnam ()) {
2206                         midnam_connection.drop_connections ();
2207                         the_instrument->DropReferences.connect (midnam_connection, invalidator (*this),
2208                                         boost::bind (&RouteTimeAxisView::drop_instrument_ref, this),
2209                                         gui_context());
2210                         pi->plugin()->UpdateMidnam.connect (midnam_connection, invalidator (*this),
2211                                         boost::bind (&RouteTimeAxisView::reread_midnam, this),
2212                                         gui_context());
2213
2214                         reread_midnam ();
2215                 }
2216         }
2217
2218         if (c.type == RouteProcessorChange::MeterPointChange) {
2219                 /* nothing to do if only the meter point has changed */
2220                 return;
2221         }
2222
2223         using namespace Menu_Helpers;
2224
2225         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2226                 (*i)->valid = false;
2227         }
2228
2229         setup_processor_menu_and_curves ();
2230
2231         bool deleted_processor_automation = false;
2232
2233         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2234
2235                 list<ProcessorAutomationInfo*>::iterator tmp;
2236
2237                 tmp = i;
2238                 ++tmp;
2239
2240                 if (!(*i)->valid) {
2241
2242                         delete *i;
2243                         processor_automation.erase (i);
2244                         deleted_processor_automation = true;
2245
2246                 }
2247
2248                 i = tmp;
2249         }
2250
2251         if (deleted_processor_automation && !no_redraw) {
2252                 request_redraw ();
2253         }
2254 }
2255
2256 boost::shared_ptr<AutomationLine>
2257 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2258 {
2259         ProcessorAutomationNode* pan;
2260
2261         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2262                 if (pan->view) {
2263                         pan->view->line();
2264                 }
2265         }
2266
2267         return boost::shared_ptr<AutomationLine>();
2268 }
2269
2270 void
2271 RouteTimeAxisView::reset_processor_automation_curves ()
2272 {
2273         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2274                 (*i)->reset();
2275         }
2276 }
2277
2278 bool
2279 RouteTimeAxisView::can_edit_name () const
2280 {
2281         /* we do not allow track name changes if it is record enabled
2282          */
2283         boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (_route));
2284         if (!trk) {
2285                 return true;
2286         }
2287         return !trk->rec_enable_control()->get_value();
2288 }
2289
2290 void
2291 RouteTimeAxisView::blink_rec_display (bool onoff)
2292 {
2293         RouteUI::blink_rec_display (onoff);
2294 }
2295
2296 void
2297 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2298 {
2299         if (_ignore_set_layer_display) {
2300                 return;
2301         }
2302
2303         if (apply_to_selection) {
2304                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2305         } else {
2306
2307                 if (_view) {
2308                         _view->set_layer_display (d);
2309                 }
2310
2311                 set_gui_property (X_("layer-display"), d);
2312         }
2313 }
2314
2315 LayerDisplay
2316 RouteTimeAxisView::layer_display () const
2317 {
2318         if (_view) {
2319                 return _view->layer_display ();
2320         }
2321
2322         /* we don't know, since we don't have a _view, so just return something */
2323         return Overlaid;
2324 }
2325
2326 void
2327 RouteTimeAxisView::fast_update ()
2328 {
2329         gm.get_level_meter().update_meters ();
2330 }
2331
2332 void
2333 RouteTimeAxisView::hide_meter ()
2334 {
2335         clear_meter ();
2336         gm.get_level_meter().hide_meters ();
2337 }
2338
2339 void
2340 RouteTimeAxisView::show_meter ()
2341 {
2342         reset_meter ();
2343 }
2344
2345 void
2346 RouteTimeAxisView::reset_meter ()
2347 {
2348         if (UIConfiguration::instance().get_show_track_meters()) {
2349                 int meter_width = 3;
2350                 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2351                         meter_width = 6;
2352                 }
2353                 gm.get_level_meter().setup_meters (height - 9, meter_width);
2354         } else {
2355                 hide_meter ();
2356         }
2357 }
2358
2359 void
2360 RouteTimeAxisView::clear_meter ()
2361 {
2362         gm.get_level_meter().clear_meters ();
2363 }
2364
2365 void
2366 RouteTimeAxisView::meter_changed ()
2367 {
2368         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2369         reset_meter();
2370         if (_route && !no_redraw && UIConfiguration::instance().get_show_track_meters()) {
2371                 request_redraw ();
2372         }
2373         // reset peak when meter point changes
2374         gm.reset_peak_display();
2375 }
2376
2377 void
2378 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2379 {
2380         reset_meter ();
2381         if (_route && !no_redraw) {
2382                 request_redraw ();
2383         }
2384 }
2385
2386 void
2387 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2388 {
2389         using namespace Menu_Helpers;
2390
2391         if (!_underlay_streams.empty()) {
2392                 MenuList& parent_items = parent_menu->items();
2393                 Menu* gs_menu = manage (new Menu);
2394                 gs_menu->set_name ("ArdourContextMenu");
2395                 MenuList& gs_items = gs_menu->items();
2396
2397                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2398
2399                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2400                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2401                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2402                 }
2403         }
2404 }
2405
2406 bool
2407 RouteTimeAxisView::set_underlay_state()
2408 {
2409         if (!underlay_xml_node) {
2410                 return false;
2411         }
2412
2413         XMLNodeList nlist = underlay_xml_node->children();
2414         XMLNodeConstIterator niter;
2415         XMLNode *child_node;
2416
2417         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2418                 child_node = *niter;
2419
2420                 if (child_node->name() != "Underlay") {
2421                         continue;
2422                 }
2423
2424                 XMLProperty const * prop = child_node->property ("id");
2425                 if (prop) {
2426                         PBD::ID id (prop->value());
2427
2428                         StripableTimeAxisView* v = _editor.get_stripable_time_axis_by_id (id);
2429
2430                         if (v) {
2431                                 add_underlay(v->view(), false);
2432                         }
2433                 }
2434         }
2435
2436         return false;
2437 }
2438
2439 void
2440 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2441 {
2442         if (!v) {
2443                 return;
2444         }
2445
2446         RouteTimeAxisView& other = v->trackview();
2447
2448         if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2449                 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2450                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2451                         abort(); /*NOTREACHED*/
2452                 }
2453
2454                 _underlay_streams.push_back(v);
2455                 other._underlay_mirrors.push_back(this);
2456
2457                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2458
2459 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2460                 if (update_xml) {
2461                         if (!underlay_xml_node) {
2462                                 underlay_xml_node = xml_node->add_child("Underlays");
2463                         }
2464
2465                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2466                         XMLProperty const * prop = node->add_property("id");
2467                         prop->set_value(v->trackview().route()->id().to_s());
2468                 }
2469 #endif
2470         }
2471 }
2472
2473 void
2474 RouteTimeAxisView::remove_underlay (StreamView* v)
2475 {
2476         if (!v) {
2477                 return;
2478         }
2479
2480         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2481         RouteTimeAxisView& other = v->trackview();
2482
2483         if (it != _underlay_streams.end()) {
2484                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2485
2486                 if (gm == other._underlay_mirrors.end()) {
2487                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2488                         abort(); /*NOTREACHED*/
2489                 }
2490
2491                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2492
2493                 _underlay_streams.erase(it);
2494                 other._underlay_mirrors.erase(gm);
2495
2496                 if (underlay_xml_node) {
2497                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2498                 }
2499         }
2500 }
2501
2502 void
2503 RouteTimeAxisView::set_button_names ()
2504 {
2505         if (_route && _route->solo_safe_control()->solo_safe()) {
2506                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2507         } else {
2508                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2509         }
2510         if (Config->get_solo_control_is_listen_control()) {
2511                 switch (Config->get_listen_position()) {
2512                         case AfterFaderListen:
2513                                 solo_button->set_text (S_("AfterFader|A"));
2514                                 set_tooltip (*solo_button, _("After-fade listen (AFL)"));
2515                                 break;
2516                         case PreFaderListen:
2517                                 solo_button->set_text (S_("PreFader|P"));
2518                                 set_tooltip (*solo_button, _("Pre-fade listen (PFL)"));
2519                         break;
2520                 }
2521         } else {
2522                 solo_button->set_text (S_("Solo|S"));
2523                 set_tooltip (*solo_button, _("Solo"));
2524         }
2525         mute_button->set_text (S_("Mute|M"));
2526 }
2527
2528 Gtk::CheckMenuItem*
2529 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2530 {
2531         Gtk::CheckMenuItem* rv = StripableTimeAxisView::automation_child_menu_item (param);
2532         if (rv) {
2533                 return rv;
2534         }
2535
2536         ParameterMenuMap::iterator i = _subplugin_menu_map.find (param);
2537         if (i != _subplugin_menu_map.end()) {
2538                 return i->second;
2539         }
2540
2541         return 0;
2542 }
2543
2544 void
2545 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2546 {
2547         boost::shared_ptr<AutomationControl> c = _route->gain_control();
2548         if (!c) {
2549                 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2550                 return;
2551         }
2552
2553         gain_track.reset (new AutomationTimeAxisView (_session,
2554                                                       _route, _route->amp(), c, param,
2555                                                       _editor,
2556                                                       *this,
2557                                                       false,
2558                                                       parent_canvas,
2559                                                       _route->amp()->describe_parameter(param)));
2560
2561         if (_view) {
2562                 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2563         }
2564
2565         add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2566 }
2567
2568 void
2569 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2570 {
2571         boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2572         if (!c || ! _route->trim()->active()) {
2573                 return;
2574         }
2575
2576         trim_track.reset (new AutomationTimeAxisView (_session,
2577                                                       _route, _route->trim(), c, param,
2578                                                       _editor,
2579                                                       *this,
2580                                                       false,
2581                                                       parent_canvas,
2582                                                       _route->trim()->describe_parameter(param)));
2583
2584         if (_view) {
2585                 _view->foreach_regionview (sigc::mem_fun (*trim_track.get(), &TimeAxisView::add_ghost));
2586         }
2587
2588         add_automation_child (Evoral::Parameter(TrimAutomation), trim_track, show);
2589 }
2590
2591 void
2592 RouteTimeAxisView::create_mute_automation_child (const Evoral::Parameter& param, bool show)
2593 {
2594         boost::shared_ptr<AutomationControl> c = _route->mute_control();
2595         if (!c) {
2596                 error << "Route has no mute automation, unable to add automation track view." << endmsg;
2597                 return;
2598         }
2599
2600         mute_track.reset (new AutomationTimeAxisView (_session,
2601                                                       _route, _route, c, param,
2602                                                       _editor,
2603                                                       *this,
2604                                                       false,
2605                                                       parent_canvas,
2606                                                       _route->describe_parameter(param)));
2607
2608         if (_view) {
2609                 _view->foreach_regionview (sigc::mem_fun (*mute_track.get(), &TimeAxisView::add_ghost));
2610         }
2611
2612         add_automation_child (Evoral::Parameter(MuteAutomation), mute_track, show);
2613 }
2614
2615 static
2616 void add_region_to_list (RegionView* rv, RegionList* l)
2617 {
2618         l->push_back (rv->region());
2619 }
2620
2621 RegionView*
2622 RouteTimeAxisView::combine_regions ()
2623 {
2624         /* as of may 2011, we do not offer uncombine for MIDI tracks
2625          */
2626
2627         if (!is_audio_track()) {
2628                 return 0;
2629         }
2630
2631         if (!_view) {
2632                 return 0;
2633         }
2634
2635         RegionList selected_regions;
2636         boost::shared_ptr<Playlist> playlist = track()->playlist();
2637
2638         _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2639
2640         if (selected_regions.size() < 2) {
2641                 return 0;
2642         }
2643
2644         playlist->clear_changes ();
2645         boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2646
2647         _session->add_command (new StatefulDiffCommand (playlist));
2648         /* make the new region be selected */
2649
2650         return _view->find_view (compound_region);
2651 }
2652
2653 void
2654 RouteTimeAxisView::uncombine_regions ()
2655 {
2656         /* as of may 2011, we do not offer uncombine for MIDI tracks
2657          */
2658         if (!is_audio_track()) {
2659                 return;
2660         }
2661
2662         if (!_view) {
2663                 return;
2664         }
2665
2666         RegionList selected_regions;
2667         boost::shared_ptr<Playlist> playlist = track()->playlist();
2668
2669         /* have to grab selected regions first because the uncombine is going
2670          * to change that in the middle of the list traverse
2671          */
2672
2673         _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2674
2675         playlist->clear_changes ();
2676
2677         for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2678                 playlist->uncombine (*i);
2679         }
2680
2681         _session->add_command (new StatefulDiffCommand (playlist));
2682 }
2683
2684 string
2685 RouteTimeAxisView::state_id() const
2686 {
2687         return string_compose ("rtav %1", _route->id().to_s());
2688 }
2689
2690
2691 void
2692 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2693 {
2694         TimeAxisView::remove_child (c);
2695
2696         boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2697         if (a) {
2698                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2699                         if (i->second == a) {
2700                                 _automation_tracks.erase (i);
2701                                 return;
2702                         }
2703                 }
2704         }
2705 }
2706
2707 Gdk::Color
2708 RouteTimeAxisView::color () const
2709 {
2710         return route_color ();
2711 }
2712
2713 bool
2714 RouteTimeAxisView::marked_for_display () const
2715 {
2716         return !_route->presentation_info().hidden();
2717 }
2718
2719 bool
2720 RouteTimeAxisView::set_marked_for_display (bool yn)
2721 {
2722         return RouteUI::mark_hidden (!yn);
2723 }