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