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