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