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