rename TempoMap::cut_time() to remove_time()
[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         pl->clear_owned_changes ();
1618         if (Config->get_edit_mode() == Ripple) {
1619                 std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
1620                 framecnt_t amount = extent.second - extent.first;
1621                 pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
1622         }
1623         pl->paste (*p, pos, ctx.times);
1624
1625         vector<Command*> cmds;
1626         pl->rdiff (cmds);
1627         _session->add_commands (cmds);
1628
1629         _session->add_command (new StatefulDiffCommand (pl));
1630
1631         return true;
1632 }
1633
1634
1635 struct PlaylistSorter {
1636     bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1637             return a->sort_id() < b->sort_id();
1638     }
1639 };
1640
1641 void
1642 RouteTimeAxisView::build_playlist_menu ()
1643 {
1644         using namespace Menu_Helpers;
1645
1646         if (!is_track()) {
1647                 return;
1648         }
1649
1650         delete playlist_action_menu;
1651         playlist_action_menu = new Menu;
1652         playlist_action_menu->set_name ("ArdourContextMenu");
1653
1654         MenuList& playlist_items = playlist_action_menu->items();
1655         playlist_action_menu->set_name ("ArdourContextMenu");
1656         playlist_items.clear();
1657
1658         RadioMenuItem::Group playlist_group;
1659         boost::shared_ptr<Track> tr = track ();
1660
1661         vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1662
1663         /* sort the playlists */
1664         PlaylistSorter cmp;
1665         sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1666
1667         /* add the playlists to the menu */
1668         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1669                 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1670                 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1671                 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1672
1673                 if (tr->playlist()->id() == (*i)->id()) {
1674                         item->set_active();
1675
1676                 }
1677         }
1678
1679         playlist_items.push_back (SeparatorElem());
1680         playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1681         playlist_items.push_back (SeparatorElem());
1682
1683         if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1684                 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1685                 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1686
1687         } else {
1688                 // Use a label which tells the user what is happening
1689                 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1690                 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1691
1692         }
1693
1694         playlist_items.push_back (SeparatorElem());
1695         playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1696         playlist_items.push_back (SeparatorElem());
1697
1698         playlist_items.push_back (MenuElem(_("Select From All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1699 }
1700
1701 void
1702 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1703 {
1704         assert (is_track());
1705
1706         // exit if we were triggered by deactivating the old playlist
1707         if (!item->get_active()) {
1708                 return;
1709         }
1710
1711         boost::shared_ptr<Playlist> pl (wpl.lock());
1712
1713         if (!pl) {
1714                 return;
1715         }
1716
1717         if (track()->playlist() == pl) {
1718                 // exit when use_playlist is called by the creation of the playlist menu
1719                 // or the playlist choice is unchanged
1720                 return;
1721         }
1722
1723         track()->use_playlist (pl);
1724         
1725         RouteGroup* rg = route_group();
1726         
1727         if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) {
1728                 std::string group_string = "." + rg->name() + ".";
1729                 
1730                 std::string take_name = pl->name();
1731                 std::string::size_type idx = take_name.find(group_string);
1732                 
1733                 if (idx == std::string::npos)
1734                         return;
1735                 
1736                 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1737                 
1738                 boost::shared_ptr<RouteList> rl (rg->route_list());
1739                 
1740                 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1741                         if ((*i) == this->route()) {
1742                                 continue;
1743                         }
1744
1745                         std::string playlist_name = (*i)->name()+group_string+take_name;
1746                         
1747                         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1748                         if (!track) {
1749                                 continue;
1750                         }
1751
1752                         if (track->freeze_state() == Track::Frozen) {
1753                                 /* Don't change playlists of frozen tracks */
1754                                 continue;
1755                         }
1756                         
1757                         boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1758                         if (!ipl) {
1759                                 // No playlist for this track for this take yet, make it
1760                                 track->use_new_playlist();
1761                                 track->playlist()->set_name(playlist_name);
1762                         } else {
1763                                 track->use_playlist(ipl);
1764                         }
1765                 }
1766         }
1767 }
1768
1769 void
1770 RouteTimeAxisView::update_playlist_tip ()
1771 {
1772         RouteGroup* rg = route_group ();
1773         if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) {
1774                 string group_string = "." + rg->name() + ".";
1775                 
1776                 string take_name = track()->playlist()->name();
1777                 string::size_type idx = take_name.find(group_string);
1778                 
1779                 if (idx != string::npos) {
1780                         /* find the bit containing the take number / name */
1781                         take_name = take_name.substr (idx + group_string.length());
1782
1783                         /* set the playlist button tooltip to the take name */
1784                         ARDOUR_UI::instance()->set_tip (
1785                                 playlist_button,
1786                                 string_compose(_("Take: %1.%2"),
1787                                         Glib::Markup::escape_text(rg->name()),
1788                                         Glib::Markup::escape_text(take_name))
1789                                 );
1790                         
1791                         return;
1792                 }
1793         }
1794
1795         /* set the playlist button tooltip to the playlist name */
1796         ARDOUR_UI::instance()->set_tip (playlist_button, _("Playlist") + std::string(": ") + Glib::Markup::escape_text(track()->playlist()->name()));
1797 }
1798
1799
1800 void
1801 RouteTimeAxisView::show_playlist_selector ()
1802 {
1803         _editor.playlist_selector().show_for (this);
1804 }
1805
1806 void
1807 RouteTimeAxisView::map_frozen ()
1808 {
1809         if (!is_track()) {
1810                 return;
1811         }
1812
1813         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1814
1815         switch (track()->freeze_state()) {
1816         case Track::Frozen:
1817                 playlist_button.set_sensitive (false);
1818                 rec_enable_button->set_sensitive (false);
1819                 break;
1820         default:
1821                 playlist_button.set_sensitive (true);
1822                 rec_enable_button->set_sensitive (true);
1823                 break;
1824         }
1825 }
1826
1827 void
1828 RouteTimeAxisView::color_handler ()
1829 {
1830         //case cTimeStretchOutline:
1831         if (timestretch_rect) {
1832                 timestretch_rect->set_outline_color (ARDOUR_UI::config()->color ("time stretch outline"));
1833         }
1834         //case cTimeStretchFill:
1835         if (timestretch_rect) {
1836                 timestretch_rect->set_fill_color (ARDOUR_UI::config()->color ("time stretch fill"));
1837         }
1838
1839         reset_meter();
1840 }
1841
1842 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1843  *  Will add track if necessary.
1844  */
1845 void
1846 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1847 {
1848         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1849         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1850
1851         if (!track) {
1852                 /* it doesn't exist yet, so we don't care about the button state: just add it */
1853                 create_automation_child (param, true);
1854         } else {
1855                 assert (menu);
1856                 bool yn = menu->get_active();
1857                 bool changed = false;
1858
1859                 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1860
1861                         /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1862                            will have done that for us.
1863                         */
1864
1865                         if (changed && !no_redraw) {
1866                                 request_redraw ();
1867                         }
1868                 }
1869         }
1870 }
1871
1872 void
1873 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1874 {
1875         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1876
1877         if (!track) {
1878                 return;
1879         }
1880
1881         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1882
1883         if (menu && !_hidden) {
1884                 ignore_toggle = true;
1885                 menu->set_active (false);
1886                 ignore_toggle = false;
1887         }
1888
1889         if (_route && !no_redraw) {
1890                 request_redraw ();
1891         }
1892 }
1893
1894 void
1895 RouteTimeAxisView::update_gain_track_visibility ()
1896 {
1897         bool const showit = gain_automation_item->get_active();
1898
1899         if (showit != string_is_affirmative (gain_track->gui_property ("visible"))) {
1900                 gain_track->set_marked_for_display (showit);
1901
1902                 /* now trigger a redisplay */
1903
1904                 if (!no_redraw) {
1905                          _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1906                 }
1907         }
1908 }
1909
1910 void
1911 RouteTimeAxisView::update_trim_track_visibility ()
1912 {
1913         bool const showit = trim_automation_item->get_active();
1914
1915         if (showit != string_is_affirmative (trim_track->gui_property ("visible"))) {
1916                 trim_track->set_marked_for_display (showit);
1917
1918                 /* now trigger a redisplay */
1919
1920                 if (!no_redraw) {
1921                          _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1922                 }
1923         }
1924 }
1925
1926 void
1927 RouteTimeAxisView::update_mute_track_visibility ()
1928 {
1929         bool const showit = mute_automation_item->get_active();
1930
1931         if (showit != string_is_affirmative (mute_track->gui_property ("visible"))) {
1932                 mute_track->set_marked_for_display (showit);
1933
1934                 /* now trigger a redisplay */
1935
1936                 if (!no_redraw) {
1937                          _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1938                 }
1939         }
1940 }
1941
1942 void
1943 RouteTimeAxisView::update_pan_track_visibility ()
1944 {
1945         bool const showit = pan_automation_item->get_active();
1946         bool changed = false;
1947
1948         for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1949                 if ((*i)->set_marked_for_display (showit)) {
1950                         changed = true;
1951                 }
1952         }
1953
1954         if (changed) {
1955                 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1956         }
1957 }
1958
1959 void
1960 RouteTimeAxisView::ensure_pan_views (bool show)
1961 {
1962         bool changed = false;
1963         for (list<boost::shared_ptr<AutomationTimeAxisView> >::iterator i = pan_tracks.begin(); i != pan_tracks.end(); ++i) {
1964                 changed = true;
1965                 (*i)->set_marked_for_display (false);
1966         }
1967         if (changed) {
1968                 _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
1969         }
1970         pan_tracks.clear();
1971
1972         if (!_route->panner()) {
1973                 return;
1974         }
1975
1976         set<Evoral::Parameter> params = _route->panner()->what_can_be_automated();
1977         set<Evoral::Parameter>::iterator p;
1978
1979         for (p = params.begin(); p != params.end(); ++p) {
1980                 boost::shared_ptr<ARDOUR::AutomationControl> pan_control = _route->pannable()->automation_control(*p);
1981
1982                 if (pan_control->parameter().type() == NullAutomation) {
1983                         error << "Pan control has NULL automation type!" << endmsg;
1984                         continue;
1985                 }
1986
1987                 if (automation_child (pan_control->parameter ()).get () == 0) {
1988
1989                         /* we don't already have an AutomationTimeAxisView for this parameter */
1990
1991                         std::string const name = _route->panner()->describe_parameter (pan_control->parameter ());
1992
1993                         boost::shared_ptr<AutomationTimeAxisView> t (
1994                                         new AutomationTimeAxisView (_session,
1995                                                 _route,
1996                                                 _route->pannable(),
1997                                                 pan_control,
1998                                                 pan_control->parameter (),
1999                                                 _editor,
2000                                                 *this,
2001                                                 false,
2002                                                 parent_canvas,
2003                                                 name)
2004                                         );
2005
2006                         pan_tracks.push_back (t);
2007                         add_automation_child (*p, t, show);
2008                 } else {
2009                         pan_tracks.push_back (automation_child (pan_control->parameter ()));
2010                 }
2011         }
2012 }
2013
2014
2015 void
2016 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
2017 {
2018         if (apply_to_selection) {
2019                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
2020         } else {
2021                 no_redraw = true;
2022
2023                 /* Show our automation */
2024
2025                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2026                         i->second->set_marked_for_display (true);
2027
2028                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2029
2030                         if (menu) {
2031                                 menu->set_active(true);
2032                         }
2033                 }
2034
2035
2036                 /* Show processor automation */
2037
2038                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2039                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2040                                 if ((*ii)->view == 0) {
2041                                         add_processor_automation_curve ((*i)->processor, (*ii)->what);
2042                                 }
2043
2044                                 (*ii)->menu_item->set_active (true);
2045                         }
2046                 }
2047
2048                 no_redraw = false;
2049
2050                 /* Redraw */
2051
2052                 request_redraw ();
2053         }
2054 }
2055
2056 void
2057 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
2058 {
2059         if (apply_to_selection) {
2060                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
2061         } else {
2062                 no_redraw = true;
2063
2064                 /* Show our automation */
2065
2066                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2067                         if (i->second->has_automation()) {
2068                                 i->second->set_marked_for_display (true);
2069
2070                                 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2071                                 if (menu) {
2072                                         menu->set_active(true);
2073                                 }
2074                         }
2075                 }
2076
2077                 /* Show processor automation */
2078
2079                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2080                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2081                                 if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
2082                                         (*ii)->menu_item->set_active (true);
2083                                 }
2084                         }
2085                 }
2086
2087                 no_redraw = false;
2088
2089                 request_redraw ();
2090         }
2091 }
2092
2093 void
2094 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
2095 {
2096         if (apply_to_selection) {
2097                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
2098         } else {
2099                 no_redraw = true;
2100
2101                 /* Hide our automation */
2102
2103                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2104                         i->second->set_marked_for_display (false);
2105
2106                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
2107
2108                         if (menu) {
2109                                 menu->set_active (false);
2110                         }
2111                 }
2112
2113                 /* Hide processor automation */
2114
2115                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2116                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2117                                 (*ii)->menu_item->set_active (false);
2118                         }
2119                 }
2120
2121                 no_redraw = false;
2122                 request_redraw ();
2123         }
2124 }
2125
2126
2127 void
2128 RouteTimeAxisView::region_view_added (RegionView* rv)
2129 {
2130         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
2131         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
2132                 boost::shared_ptr<AutomationTimeAxisView> atv;
2133
2134                 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
2135                         atv->add_ghost(rv);
2136                 }
2137         }
2138
2139         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
2140                 (*i)->add_ghost(rv);
2141         }
2142 }
2143
2144 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
2145 {
2146         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
2147                 delete *i;
2148         }
2149 }
2150
2151
2152 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
2153 {
2154         parent.remove_processor_automation_node (this);
2155 }
2156
2157 void
2158 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
2159 {
2160         if (pan->view) {
2161                 remove_child (pan->view);
2162         }
2163 }
2164
2165 RouteTimeAxisView::ProcessorAutomationNode*
2166 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2167 {
2168         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2169
2170                 if ((*i)->processor == processor) {
2171
2172                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
2173                                 if ((*ii)->what == what) {
2174                                         return *ii;
2175                                 }
2176                         }
2177                 }
2178         }
2179
2180         return 0;
2181 }
2182
2183 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
2184 void
2185 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2186 {
2187         string name;
2188         ProcessorAutomationNode* pan;
2189
2190         if ((pan = find_processor_automation_node (processor, what)) == 0) {
2191                 /* session state may never have been saved with new plugin */
2192                 error << _("programming error: ")
2193                       << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
2194                                          processor->name(), what.type(), (int) what.channel(), what.id() )
2195                       << endmsg;
2196                 abort(); /*NOTREACHED*/
2197                 return;
2198         }
2199
2200         if (pan->view) {
2201                 return;
2202         }
2203
2204         boost::shared_ptr<AutomationControl> control
2205                 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
2206         
2207         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
2208                 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
2209                                             _editor, *this, false, parent_canvas, 
2210                                             processor->describe_parameter (what), processor->name()));
2211
2212         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
2213
2214         add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
2215
2216         if (_view) {
2217                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
2218         }
2219 }
2220
2221 void
2222 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
2223 {
2224         if (!_hidden) {
2225                 pan->menu_item->set_active (false);
2226         }
2227
2228         if (!no_redraw) {
2229                 request_redraw ();
2230         }
2231 }
2232
2233 void
2234 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
2235 {
2236         boost::shared_ptr<Processor> processor (p.lock ());
2237
2238         if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
2239                 /* The Amp processor is a special case and is dealt with separately */
2240                 return;
2241         }
2242
2243         set<Evoral::Parameter> existing;
2244
2245         processor->what_has_data (existing);
2246
2247         for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
2248                 
2249                 Evoral::Parameter param (*i);
2250                 boost::shared_ptr<AutomationLine> al;
2251
2252                 if ((al = find_processor_automation_curve (processor, param)) != 0) {
2253                         al->queue_reset ();
2254                 } else {
2255                         add_processor_automation_curve (processor, param);
2256                 }
2257         }
2258 }
2259
2260 void
2261 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
2262 {
2263         using namespace Menu_Helpers;
2264
2265         add_child (track);
2266
2267         track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
2268
2269         _automation_tracks[param] = track;
2270
2271         /* existing state overrides "show" argument */
2272         string s = track->gui_property ("visible");
2273         if (!s.empty()) { 
2274                 show = string_is_affirmative (s);
2275         }
2276
2277         /* this might or might not change the visibility status, so don't rely on it */
2278         track->set_marked_for_display (show);
2279
2280         if (show && !no_redraw) {
2281                 request_redraw ();
2282         }
2283
2284         if (!ARDOUR::parameter_is_midi((AutomationType)param.type())) {
2285                 /* MIDI-related parameters are always in the menu, there's no
2286                    reason to rebuild the menu just because we added a automation
2287                    lane for one of them. But if we add a non-MIDI automation
2288                    lane, then we need to invalidate the display menu.
2289                 */
2290                 delete display_menu;
2291                 display_menu = 0;
2292         }
2293 }
2294
2295 void
2296 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2297 {
2298         boost::shared_ptr<Processor> processor (p.lock ());
2299
2300         if (!processor || !processor->display_to_user ()) {
2301                 return;
2302         }
2303
2304         /* we use this override to veto the Amp processor from the plugin menu,
2305            as its automation lane can be accessed using the special "Fader" menu
2306            option
2307         */
2308
2309         if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2310                 return;
2311         }
2312
2313         using namespace Menu_Helpers;
2314         ProcessorAutomationInfo *rai;
2315         list<ProcessorAutomationInfo*>::iterator x;
2316
2317         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2318
2319         if (automatable.empty()) {
2320                 return;
2321         }
2322
2323         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2324                 if ((*x)->processor == processor) {
2325                         break;
2326                 }
2327         }
2328
2329         if (x == processor_automation.end()) {
2330
2331                 rai = new ProcessorAutomationInfo (processor);
2332                 processor_automation.push_back (rai);
2333
2334         } else {
2335
2336                 rai = *x;
2337
2338         }
2339
2340         /* any older menu was deleted at the top of processors_changed()
2341            when we cleared the subplugin menu.
2342         */
2343
2344         rai->menu = manage (new Menu);
2345         MenuList& items = rai->menu->items();
2346         rai->menu->set_name ("ArdourContextMenu");
2347
2348         items.clear ();
2349
2350         std::set<Evoral::Parameter> has_visible_automation;
2351         AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2352
2353         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2354
2355                 ProcessorAutomationNode* pan;
2356                 Gtk::CheckMenuItem* mitem;
2357
2358                 string name = processor->describe_parameter (*i);
2359
2360                 items.push_back (CheckMenuElem (name));
2361                 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2362                 
2363                 _subplugin_menu_map[*i] = mitem;
2364
2365                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2366                         mitem->set_active(true);
2367                 }
2368
2369                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2370
2371                         /* new item */
2372
2373                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2374
2375                         rai->lines.push_back (pan);
2376
2377                 } else {
2378
2379                         pan->menu_item = mitem;
2380
2381                 }
2382
2383                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2384         }
2385
2386         /* add the menu for this processor, because the subplugin
2387            menu is always cleared at the top of processors_changed().
2388            this is the result of some poor design in gtkmm and/or
2389            GTK+.
2390         */
2391
2392         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2393         rai->valid = true;
2394 }
2395
2396 void
2397 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2398                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2399 {
2400         bool showit = pan->menu_item->get_active();
2401         bool redraw = false;
2402
2403         if (pan->view == 0 && showit) {
2404                 add_processor_automation_curve (rai->processor, pan->what);
2405                 redraw = true;
2406         }
2407
2408         if (pan->view && pan->view->set_marked_for_display (showit)) {
2409                 redraw = true;
2410         }
2411         
2412         if (redraw && !no_redraw) {
2413                 request_redraw ();
2414         }
2415 }
2416
2417 void
2418 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2419 {
2420         if (c.type == RouteProcessorChange::MeterPointChange) {
2421                 /* nothing to do if only the meter point has changed */
2422                 return;
2423         }
2424
2425         using namespace Menu_Helpers;
2426
2427         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2428                 (*i)->valid = false;
2429         }
2430
2431         setup_processor_menu_and_curves ();
2432
2433         bool deleted_processor_automation = false;
2434
2435         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2436
2437                 list<ProcessorAutomationInfo*>::iterator tmp;
2438
2439                 tmp = i;
2440                 ++tmp;
2441
2442                 if (!(*i)->valid) {
2443
2444                         delete *i;
2445                         processor_automation.erase (i);
2446                         deleted_processor_automation = true;
2447
2448                 }
2449
2450                 i = tmp;
2451         }
2452
2453         if (deleted_processor_automation && !no_redraw) {
2454                 request_redraw ();
2455         }
2456 }
2457
2458 boost::shared_ptr<AutomationLine>
2459 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2460 {
2461         ProcessorAutomationNode* pan;
2462
2463         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2464                 if (pan->view) {
2465                         pan->view->line();
2466                 }
2467         }
2468
2469         return boost::shared_ptr<AutomationLine>();
2470 }
2471
2472 void
2473 RouteTimeAxisView::reset_processor_automation_curves ()
2474 {
2475         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2476                 (*i)->reset();
2477         }
2478 }
2479
2480 bool
2481 RouteTimeAxisView::can_edit_name () const
2482 {
2483         /* we do not allow track name changes if it is record enabled
2484          */
2485         return !_route->record_enabled();
2486 }
2487
2488 void
2489 RouteTimeAxisView::blink_rec_display (bool onoff)
2490 {
2491         RouteUI::blink_rec_display (onoff);
2492 }
2493
2494 void
2495 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2496 {
2497         if (_ignore_set_layer_display) {
2498                 return;
2499         }
2500         
2501         if (apply_to_selection) {
2502                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2503         } else {
2504
2505                 if (_view) {
2506                         _view->set_layer_display (d);
2507                 }
2508
2509                 set_gui_property (X_("layer-display"), enum_2_string (d));
2510         }
2511 }
2512
2513 LayerDisplay
2514 RouteTimeAxisView::layer_display () const
2515 {
2516         if (_view) {
2517                 return _view->layer_display ();
2518         }
2519
2520         /* we don't know, since we don't have a _view, so just return something */
2521         return Overlaid;
2522 }
2523
2524
2525
2526 boost::shared_ptr<AutomationTimeAxisView>
2527 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2528 {
2529         AutomationTracks::iterator i = _automation_tracks.find(param);
2530         if (i != _automation_tracks.end()) {
2531                 return i->second;
2532         } else {
2533                 return boost::shared_ptr<AutomationTimeAxisView>();
2534         }
2535 }
2536
2537 void
2538 RouteTimeAxisView::fast_update ()
2539 {
2540         gm.get_level_meter().update_meters ();
2541 }
2542
2543 void
2544 RouteTimeAxisView::hide_meter ()
2545 {
2546         clear_meter ();
2547         gm.get_level_meter().hide_meters ();
2548 }
2549
2550 void
2551 RouteTimeAxisView::show_meter ()
2552 {
2553         reset_meter ();
2554 }
2555
2556 void
2557 RouteTimeAxisView::reset_meter ()
2558 {
2559         if (ARDOUR_UI::config()->get_show_track_meters()) {
2560                 int meter_width = 3;
2561                 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2562                         meter_width = 6;
2563                 }
2564                 gm.get_level_meter().setup_meters (height - 9, meter_width);
2565         } else {
2566                 hide_meter ();
2567         }
2568 }
2569
2570 void
2571 RouteTimeAxisView::clear_meter ()
2572 {
2573         gm.get_level_meter().clear_meters ();
2574 }
2575
2576 void
2577 RouteTimeAxisView::meter_changed ()
2578 {
2579         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2580         reset_meter();
2581         if (_route && !no_redraw && ARDOUR_UI::config()->get_show_track_meters()) {
2582                 request_redraw ();
2583         }
2584         // reset peak when meter point changes
2585         gm.reset_peak_display();
2586 }
2587
2588 void
2589 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2590 {
2591         reset_meter ();
2592         if (_route && !no_redraw) {
2593                 request_redraw ();
2594         }
2595 }
2596
2597 void
2598 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2599 {
2600         using namespace Menu_Helpers;
2601
2602         if (!_underlay_streams.empty()) {
2603                 MenuList& parent_items = parent_menu->items();
2604                 Menu* gs_menu = manage (new Menu);
2605                 gs_menu->set_name ("ArdourContextMenu");
2606                 MenuList& gs_items = gs_menu->items();
2607
2608                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2609
2610                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2611                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2612                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2613                 }
2614         }
2615 }
2616
2617 bool
2618 RouteTimeAxisView::set_underlay_state()
2619 {
2620         if (!underlay_xml_node) {
2621                 return false;
2622         }
2623
2624         XMLNodeList nlist = underlay_xml_node->children();
2625         XMLNodeConstIterator niter;
2626         XMLNode *child_node;
2627
2628         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2629                 child_node = *niter;
2630
2631                 if (child_node->name() != "Underlay") {
2632                         continue;
2633                 }
2634
2635                 XMLProperty* prop = child_node->property ("id");
2636                 if (prop) {
2637                         PBD::ID id (prop->value());
2638
2639                         RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2640
2641                         if (v) {
2642                                 add_underlay(v->view(), false);
2643                         }
2644                 }
2645         }
2646
2647         return false;
2648 }
2649
2650 void
2651 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2652 {
2653         if (!v) {
2654                 return;
2655         }
2656
2657         RouteTimeAxisView& other = v->trackview();
2658
2659         if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2660                 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2661                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2662                         abort(); /*NOTREACHED*/
2663                 }
2664
2665                 _underlay_streams.push_back(v);
2666                 other._underlay_mirrors.push_back(this);
2667
2668                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2669
2670 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2671                 if (update_xml) {
2672                         if (!underlay_xml_node) {
2673                                 underlay_xml_node = xml_node->add_child("Underlays");
2674                         }
2675
2676                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2677                         XMLProperty* prop = node->add_property("id");
2678                         prop->set_value(v->trackview().route()->id().to_s());
2679                 }
2680 #endif
2681         }
2682 }
2683
2684 void
2685 RouteTimeAxisView::remove_underlay (StreamView* v)
2686 {
2687         if (!v) {
2688                 return;
2689         }
2690
2691         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2692         RouteTimeAxisView& other = v->trackview();
2693
2694         if (it != _underlay_streams.end()) {
2695                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2696
2697                 if (gm == other._underlay_mirrors.end()) {
2698                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2699                         abort(); /*NOTREACHED*/
2700                 }
2701
2702                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2703
2704                 _underlay_streams.erase(it);
2705                 other._underlay_mirrors.erase(gm);
2706
2707                 if (underlay_xml_node) {
2708                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2709                 }
2710         }
2711 }
2712
2713 void
2714 RouteTimeAxisView::set_button_names ()
2715 {
2716         if (_route && _route->solo_safe()) {
2717                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2718         } else {
2719                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2720         }
2721         if (Config->get_solo_control_is_listen_control()) {
2722                 switch (Config->get_listen_position()) {
2723                         case AfterFaderListen:
2724                                 solo_button->set_text (S_("AfterFader|A"));
2725                                 ARDOUR_UI::instance()->set_tip (*solo_button, _("After-fade listen (AFL)"));
2726                                 break;
2727                         case PreFaderListen:
2728                                 solo_button->set_text (S_("PreFader|P"));
2729                                 ARDOUR_UI::instance()->set_tip (*solo_button, _("Pre-fade listen (PFL)"));
2730                         break;
2731                 }
2732         } else {
2733                 solo_button->set_text (S_("Solo|S"));
2734                 ARDOUR_UI::instance()->set_tip (*solo_button, _("Solo"));
2735         }
2736         mute_button->set_text (S_("Mute|M"));
2737 }
2738
2739 Gtk::CheckMenuItem*
2740 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2741 {
2742         ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2743         if (i != _main_automation_menu_map.end()) {
2744                 return i->second;
2745         }
2746
2747         i = _subplugin_menu_map.find (param);
2748         if (i != _subplugin_menu_map.end()) {
2749                 return i->second;
2750         }
2751
2752         return 0;
2753 }
2754
2755 void
2756 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2757 {
2758         boost::shared_ptr<AutomationControl> c = _route->gain_control();
2759         if (!c) {
2760                 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2761                 return;
2762         }
2763
2764         gain_track.reset (new AutomationTimeAxisView (_session,
2765                                                       _route, _route->amp(), c, param,
2766                                                       _editor,
2767                                                       *this,
2768                                                       false,
2769                                                       parent_canvas,
2770                                                       _route->amp()->describe_parameter(param)));
2771
2772         if (_view) {
2773                 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2774         }
2775
2776         add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2777 }
2778
2779 void
2780 RouteTimeAxisView::create_trim_automation_child (const Evoral::Parameter& param, bool show)
2781 {
2782         boost::shared_ptr<AutomationControl> c = _route->trim()->gain_control();
2783         if (!c || ! _route->trim()->active()) {
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 }