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