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