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