0fbbd834701a335fdb7176707e22de140015a98c
[ardour.git] / gtk2_ardour / route_time_axis.cc
1 /*
2     Copyright (C) 2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cstdlib>
20 #include <cmath>
21 #include <cassert>
22
23 #include <algorithm>
24 #include <string>
25 #include <vector>
26 #include <map>
27 #include <utility>
28
29 #include <sigc++/bind.h>
30
31 #include "pbd/error.h"
32 #include "pbd/stl_delete.h"
33 #include "pbd/whitespace.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/enumwriter.h"
36 #include "pbd/stateful_diff_command.h"
37
38 #include <gtkmm/menu.h>
39 #include <gtkmm/menuitem.h>
40 #include <gtkmm2ext/gtk_ui.h>
41 #include <gtkmm2ext/selector.h>
42 #include <gtkmm2ext/bindable_button.h>
43 #include <gtkmm2ext/utils.h>
44
45 #include "ardour/amp.h"
46 #include "ardour/event_type_map.h"
47 #include "ardour/processor.h"
48 #include "ardour/profile.h"
49 #include "ardour/route_group.h"
50 #include "ardour/session.h"
51 #include "ardour/session_playlists.h"
52 #include "evoral/Parameter.hpp"
53
54 #include "ardour_ui.h"
55 #include "ardour_button.h"
56 #include "debug.h"
57 #include "global_signals.h"
58 #include "route_time_axis.h"
59 #include "automation_time_axis.h"
60 #include "canvas_impl.h"
61 #include "enums.h"
62 #include "gui_thread.h"
63 #include "keyboard.h"
64 #include "playlist_selector.h"
65 #include "point_selection.h"
66 #include "prompter.h"
67 #include "public_editor.h"
68 #include "region_view.h"
69 #include "rgb_macros.h"
70 #include "selection.h"
71 #include "simplerect.h"
72 #include "streamview.h"
73 #include "utils.h"
74 #include "route_group_menu.h"
75
76 #include "ardour/track.h"
77
78 #include "i18n.h"
79
80 using namespace ARDOUR;
81 using namespace PBD;
82 using namespace Gtkmm2ext;
83 using namespace Gtk;
84 using namespace Editing;
85 using namespace std;
86 using std::list;
87
88 Glib::RefPtr<Gdk::Pixbuf> RouteTimeAxisView::slider;
89 Glib::RefPtr<Gdk::Pixbuf> RouteTimeAxisView::slider_desensitised;
90
91 void
92 RouteTimeAxisView::setup_slider_pix ()
93 {
94         if ((slider = ::get_icon ("fader_belt_h_medium")) == 0) {
95                 throw failed_constructor ();
96         }
97
98         if ((slider_desensitised = ::get_icon ("fader_belt_h_medium_desensitised")) == 0) {
99                 throw failed_constructor ();
100         }
101 }
102
103 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
104         : AxisView(sess)
105         , RouteUI(sess)
106         , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
107         , _view (0)
108         , parent_canvas (canvas)
109         , no_redraw (false)
110         , button_table (3, 3)
111         , route_group_button (_("g"))
112         , playlist_button (_("p"))
113         , automation_button (_("a"))
114         , automation_action_menu (0)
115         , plugins_submenu_item (0)
116         , route_group_menu (0)
117         , playlist_action_menu (0)
118         , mode_menu (0)
119         , color_mode_menu (0)
120         , gm (sess, slider, slider_desensitised, true, 125)
121         , _ignore_set_layer_display (false)
122 {
123 }
124
125 void
126 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
127 {
128         RouteUI::set_route (rt);
129         
130         gm.set_controls (_route, _route->shared_peak_meter(), _route->amp());
131         gm.get_level_meter().set_no_show_all();
132         gm.get_level_meter().setup_meters(50);
133         gm.update_gain_sensitive ();
134
135         string str = gui_property ("height");
136         if (!str.empty()) {
137                 set_height (atoi (str));
138         } else {
139                 set_height (preset_height (HeightNormal));
140         }
141
142         if (!_route->is_hidden()) {
143                 if (gui_property ("visible").empty()) {
144                         set_gui_property ("visible", true);
145                 }
146         } else {
147                 set_gui_property ("visible", false);
148         }
149
150         mute_changed (0);
151         update_solo_display ();
152
153         timestretch_rect = 0;
154         no_redraw = false;
155
156         ignore_toggle = false;
157
158         route_group_button.set_name ("route button");
159         playlist_button.set_name ("route button");
160         automation_button.set_name ("route button");
161
162         route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
163         playlist_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click));
164         automation_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click));
165
166         if (is_track()) {
167
168                 /* use icon */
169                 
170                 switch (track()->mode()) {
171                 case ARDOUR::Normal:
172                 case ARDOUR::NonLayered:
173                         rec_enable_button->set_image (::get_icon (X_("record_normal_red")));
174                         break;
175                 case ARDOUR::Destructive:
176                         rec_enable_button->set_image (::get_icon (X_("record_tape_red")));
177                         break;
178                 }
179
180                 controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
181
182                 if (is_midi_track()) {
183                         ARDOUR_UI::instance()->set_tip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
184                 } else {
185                         ARDOUR_UI::instance()->set_tip(*rec_enable_button, _("Record"));
186                 }
187
188                 rec_enable_button->set_sensitive (_session->writable());
189                 
190                 /* set playlist button tip to the current playlist, and make it update when it changes */
191                 update_playlist_tip ();
192                 track()->PlaylistChanged.connect (*this, invalidator (*this), ui_bind(&RouteTimeAxisView::update_playlist_tip, this), gui_context());
193                 
194         }
195         
196         controls_hbox.pack_start(gm.get_level_meter(), false, false);
197         _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
198         _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
199         _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
200
201         controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
202
203         if (!_route->is_master()) {
204                 controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
205         }
206
207         controls_table.attach (route_group_button, 7, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
208 //      Gtk::VBox* pad = manage (new Gtk::VBox);
209 //      pad->pack_start (gm.get_gain_slider(), false, false);
210 //      pad->pack_start (*manage (new Gtk::Label), true, true);
211 //      pad->show_all ();
212         controls_table.attach (gm.get_gain_slider(), 0, 5, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 3, 0);
213
214         ARDOUR_UI::instance()->set_tip(*solo_button,_("Solo"));
215         ARDOUR_UI::instance()->set_tip(*mute_button,_("Mute"));
216         ARDOUR_UI::instance()->set_tip(route_group_button, _("Route Group"));
217
218         if (is_midi_track()) {
219                 ARDOUR_UI::instance()->set_tip(automation_button, _("MIDI Controllers and Automation"));
220         } else {
221                 ARDOUR_UI::instance()->set_tip(automation_button, _("Automation"));
222         }
223
224         label_view ();
225
226         controls_table.attach (automation_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
227
228         if (is_track() && track()->mode() == ARDOUR::Normal) {
229                 controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
230         }
231
232         _y_position = -1;
233
234         _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
235         _route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::route_property_changed, this, _1), gui_context());
236
237         if (is_track()) {
238
239                 str = gui_property ("layer-display");
240                 if (!str.empty()) {
241                         set_layer_display (LayerDisplay (string_2_enum (str, _view->layer_display ())));
242                 }
243
244                 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
245                 track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
246
247                 /* pick up the correct freeze state */
248                 map_frozen ();
249         }
250
251         _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 ("GainFader");
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, Glib::Markup::escape_text(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"),
1605                                         Glib::Markup::escape_text(rg->name()),
1606                                         Glib::Markup::escape_text(take_name))
1607                                 );
1608                         
1609                         return;
1610                 }
1611         }
1612
1613         /* set the playlist button tooltip to the playlist name */
1614         ARDOUR_UI::instance()->set_tip (playlist_button, _("Playlist") + std::string(": ") + Glib::Markup::escape_text(track()->playlist()->name()));
1615 }
1616
1617
1618 void
1619 RouteTimeAxisView::show_playlist_selector ()
1620 {
1621         _editor.playlist_selector().show_for (this);
1622 }
1623
1624 void
1625 RouteTimeAxisView::map_frozen ()
1626 {
1627         if (!is_track()) {
1628                 return;
1629         }
1630
1631         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1632
1633         switch (track()->freeze_state()) {
1634         case Track::Frozen:
1635                 playlist_button.set_sensitive (false);
1636                 rec_enable_button->set_sensitive (false);
1637                 break;
1638         default:
1639                 playlist_button.set_sensitive (true);
1640                 rec_enable_button->set_sensitive (true);
1641                 break;
1642         }
1643 }
1644
1645 void
1646 RouteTimeAxisView::color_handler ()
1647 {
1648         //case cTimeStretchOutline:
1649         if (timestretch_rect) {
1650                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
1651         }
1652         //case cTimeStretchFill:
1653         if (timestretch_rect) {
1654                 timestretch_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
1655         }
1656
1657         reset_meter();
1658 }
1659
1660 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1661  *  Will add track if necessary.
1662  */
1663 void
1664 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1665 {
1666         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1667         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1668
1669         if (!track) {
1670                 /* it doesn't exist yet, so we don't care about the button state: just add it */
1671                 create_automation_child (param, true);
1672         } else {
1673                 assert (menu);
1674                 bool yn = menu->get_active();
1675                 bool changed = false;
1676
1677                 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1678
1679                         /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1680                            will have done that for us.
1681                         */
1682
1683                         if (changed && !no_redraw) {
1684                                 request_redraw ();
1685                         }
1686                 }
1687         }
1688 }
1689
1690 void
1691 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1692 {
1693         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1694
1695         if (!track) {
1696                 return;
1697         }
1698
1699         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1700
1701         if (menu && !_hidden) {
1702                 ignore_toggle = true;
1703                 menu->set_active (false);
1704                 ignore_toggle = false;
1705         }
1706
1707         if (_route && !no_redraw) {
1708                 request_redraw ();
1709         }
1710 }
1711
1712
1713 void
1714 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
1715 {
1716         if (apply_to_selection) {
1717                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
1718         } else {
1719                 no_redraw = true;
1720
1721                 /* Show our automation */
1722
1723                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1724                         i->second->set_marked_for_display (true);
1725
1726                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1727
1728                         if (menu) {
1729                                 menu->set_active(true);
1730                         }
1731                 }
1732
1733
1734                 /* Show processor automation */
1735
1736                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1737                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1738                                 if ((*ii)->view == 0) {
1739                                         add_processor_automation_curve ((*i)->processor, (*ii)->what);
1740                                 }
1741
1742                                 (*ii)->menu_item->set_active (true);
1743                         }
1744                 }
1745
1746                 no_redraw = false;
1747
1748                 /* Redraw */
1749
1750                 request_redraw ();
1751         }
1752 }
1753
1754 void
1755 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
1756 {
1757         if (apply_to_selection) {
1758                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
1759         } else {
1760                 no_redraw = true;
1761
1762                 /* Show our automation */
1763
1764                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1765                         if (i->second->has_automation()) {
1766                                 i->second->set_marked_for_display (true);
1767
1768                                 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1769                                 if (menu) {
1770                                         menu->set_active(true);
1771                                 }
1772                         }
1773                 }
1774
1775                 /* Show processor automation */
1776
1777                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1778                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1779                                 if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
1780                                         (*ii)->menu_item->set_active (true);
1781                                 }
1782                         }
1783                 }
1784
1785                 no_redraw = false;
1786
1787                 request_redraw ();
1788         }
1789 }
1790
1791 void
1792 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
1793 {
1794         if (apply_to_selection) {
1795                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
1796         } else {
1797                 no_redraw = true;
1798
1799                 /* Hide our automation */
1800
1801                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1802                         i->second->set_marked_for_display (false);
1803
1804                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1805
1806                         if (menu) {
1807                                 menu->set_active (false);
1808                         }
1809                 }
1810
1811                 /* Hide processor automation */
1812
1813                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1814                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1815                                 (*ii)->menu_item->set_active (false);
1816                         }
1817                 }
1818
1819                 no_redraw = false;
1820                 request_redraw ();
1821         }
1822 }
1823
1824
1825 void
1826 RouteTimeAxisView::region_view_added (RegionView* rv)
1827 {
1828         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
1829         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1830                 boost::shared_ptr<AutomationTimeAxisView> atv;
1831
1832                 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1833                         atv->add_ghost(rv);
1834                 }
1835         }
1836
1837         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
1838                 (*i)->add_ghost(rv);
1839         }
1840 }
1841
1842 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1843 {
1844         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1845                 delete *i;
1846         }
1847 }
1848
1849
1850 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1851 {
1852         parent.remove_processor_automation_node (this);
1853 }
1854
1855 void
1856 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1857 {
1858         if (pan->view) {
1859                 remove_child (pan->view);
1860         }
1861 }
1862
1863 RouteTimeAxisView::ProcessorAutomationNode*
1864 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1865 {
1866         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1867
1868                 if ((*i)->processor == processor) {
1869
1870                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1871                                 if ((*ii)->what == what) {
1872                                         return *ii;
1873                                 }
1874                         }
1875                 }
1876         }
1877
1878         return 0;
1879 }
1880
1881 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
1882 void
1883 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1884 {
1885         string name;
1886         ProcessorAutomationNode* pan;
1887
1888         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1889                 /* session state may never have been saved with new plugin */
1890                 error << _("programming error: ")
1891                       << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
1892                                          processor->name(), what.type(), (int) what.channel(), what.id() )
1893                       << endmsg;
1894                 /*NOTREACHED*/
1895                 return;
1896         }
1897
1898         if (pan->view) {
1899                 return;
1900         }
1901
1902         boost::shared_ptr<AutomationControl> control
1903                 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
1904         
1905         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
1906                 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
1907                                             _editor, *this, false, parent_canvas, 
1908                                             processor->describe_parameter (what), processor->name()));
1909
1910         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
1911
1912         add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
1913
1914         if (_view) {
1915                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
1916         }
1917 }
1918
1919 void
1920 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
1921 {
1922         if (!_hidden) {
1923                 pan->menu_item->set_active (false);
1924         }
1925
1926         if (!no_redraw) {
1927                 request_redraw ();
1928         }
1929 }
1930
1931 void
1932 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
1933 {
1934         boost::shared_ptr<Processor> processor (p.lock ());
1935
1936         if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
1937                 /* The Amp processor is a special case and is dealt with separately */
1938                 return;
1939         }
1940
1941         set<Evoral::Parameter> existing;
1942
1943         processor->what_has_data (existing);
1944
1945         for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
1946                 
1947                 Evoral::Parameter param (*i);
1948                 boost::shared_ptr<AutomationLine> al;
1949
1950                 if ((al = find_processor_automation_curve (processor, param)) != 0) {
1951                         al->queue_reset ();
1952                 } else {
1953                         add_processor_automation_curve (processor, param);
1954                 }
1955         }
1956 }
1957
1958 void
1959 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
1960 {
1961         using namespace Menu_Helpers;
1962
1963         add_child (track);
1964
1965         track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
1966
1967         _automation_tracks[param] = track;
1968
1969         /* existing state overrides "show" argument */
1970         string s = track->gui_property ("visible");
1971         if (!s.empty()) { 
1972                 show = string_is_affirmative (s);
1973         }
1974
1975         /* this might or might not change the visibility status, so don't rely on it */
1976         track->set_marked_for_display (show);
1977
1978         if (show && !no_redraw) {
1979                 request_redraw ();
1980         }
1981
1982         if (!EventTypeMap::instance().is_midi_parameter(param)) {
1983                 /* MIDI-related parameters are always in the menu, there's no
1984                    reason to rebuild the menu just because we added a automation
1985                    lane for one of them. But if we add a non-MIDI automation
1986                    lane, then we need to invalidate the display menu.
1987                 */
1988                 delete display_menu;
1989                 display_menu = 0;
1990         }
1991 }
1992
1993 void
1994 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
1995 {
1996         boost::shared_ptr<Processor> processor (p.lock ());
1997
1998         if (!processor || !processor->display_to_user ()) {
1999                 return;
2000         }
2001
2002         /* we use this override to veto the Amp processor from the plugin menu,
2003            as its automation lane can be accessed using the special "Fader" menu
2004            option
2005         */
2006
2007         if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2008                 return;
2009         }
2010
2011         using namespace Menu_Helpers;
2012         ProcessorAutomationInfo *rai;
2013         list<ProcessorAutomationInfo*>::iterator x;
2014
2015         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2016
2017         if (automatable.empty()) {
2018                 return;
2019         }
2020
2021         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2022                 if ((*x)->processor == processor) {
2023                         break;
2024                 }
2025         }
2026
2027         if (x == processor_automation.end()) {
2028
2029                 rai = new ProcessorAutomationInfo (processor);
2030                 processor_automation.push_back (rai);
2031
2032         } else {
2033
2034                 rai = *x;
2035
2036         }
2037
2038         /* any older menu was deleted at the top of processors_changed()
2039            when we cleared the subplugin menu.
2040         */
2041
2042         rai->menu = manage (new Menu);
2043         MenuList& items = rai->menu->items();
2044         rai->menu->set_name ("ArdourContextMenu");
2045
2046         items.clear ();
2047
2048         std::set<Evoral::Parameter> has_visible_automation;
2049         AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2050
2051         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2052
2053                 ProcessorAutomationNode* pan;
2054                 CheckMenuItem* mitem;
2055
2056                 string name = processor->describe_parameter (*i);
2057
2058                 items.push_back (CheckMenuElem (name));
2059                 mitem = dynamic_cast<CheckMenuItem*> (&items.back());
2060                 
2061                 _subplugin_menu_map[*i] = mitem;
2062
2063                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2064                         mitem->set_active(true);
2065                 }
2066
2067                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2068
2069                         /* new item */
2070
2071                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2072
2073                         rai->lines.push_back (pan);
2074
2075                 } else {
2076
2077                         pan->menu_item = mitem;
2078
2079                 }
2080
2081                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2082         }
2083
2084         /* add the menu for this processor, because the subplugin
2085            menu is always cleared at the top of processors_changed().
2086            this is the result of some poor design in gtkmm and/or
2087            GTK+.
2088         */
2089
2090         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2091         rai->valid = true;
2092 }
2093
2094 void
2095 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2096                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2097 {
2098         bool showit = pan->menu_item->get_active();
2099         bool redraw = false;
2100
2101         if (pan->view == 0 && showit) {
2102                 add_processor_automation_curve (rai->processor, pan->what);
2103                 redraw = true;
2104         }
2105
2106         if (pan->view && pan->view->set_marked_for_display (showit)) {
2107                 redraw = true;
2108         }
2109         
2110         if (redraw && !no_redraw) {
2111                 request_redraw ();
2112         }
2113 }
2114
2115 void
2116 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2117 {
2118         if (c.type == RouteProcessorChange::MeterPointChange) {
2119                 /* nothing to do if only the meter point has changed */
2120                 return;
2121         }
2122
2123         using namespace Menu_Helpers;
2124
2125         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2126                 (*i)->valid = false;
2127         }
2128
2129         setup_processor_menu_and_curves ();
2130
2131         bool deleted_processor_automation = false;
2132
2133         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2134
2135                 list<ProcessorAutomationInfo*>::iterator tmp;
2136
2137                 tmp = i;
2138                 ++tmp;
2139
2140                 if (!(*i)->valid) {
2141
2142                         delete *i;
2143                         processor_automation.erase (i);
2144                         deleted_processor_automation = true;
2145
2146                 }
2147
2148                 i = tmp;
2149         }
2150
2151         if (deleted_processor_automation && !no_redraw) {
2152                 request_redraw ();
2153         }
2154 }
2155
2156 boost::shared_ptr<AutomationLine>
2157 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2158 {
2159         ProcessorAutomationNode* pan;
2160
2161         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2162                 if (pan->view) {
2163                         pan->view->line();
2164                 }
2165         }
2166
2167         return boost::shared_ptr<AutomationLine>();
2168 }
2169
2170 void
2171 RouteTimeAxisView::reset_processor_automation_curves ()
2172 {
2173         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2174                 (*i)->reset();
2175         }
2176 }
2177
2178 void
2179 RouteTimeAxisView::update_rec_display ()
2180 {
2181         RouteUI::update_rec_display ();
2182         name_entry.set_sensitive (!_route->record_enabled());
2183 }
2184
2185 void
2186 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2187 {
2188         if (_ignore_set_layer_display) {
2189                 return;
2190         }
2191         
2192         if (apply_to_selection) {
2193                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2194         } else {
2195
2196                 if (_view) {
2197                         _view->set_layer_display (d);
2198                 }
2199
2200                 set_gui_property (X_("layer-display"), enum_2_string (d));
2201         }
2202 }
2203
2204 LayerDisplay
2205 RouteTimeAxisView::layer_display () const
2206 {
2207         if (_view) {
2208                 return _view->layer_display ();
2209         }
2210
2211         /* we don't know, since we don't have a _view, so just return something */
2212         return Overlaid;
2213 }
2214
2215
2216
2217 boost::shared_ptr<AutomationTimeAxisView>
2218 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2219 {
2220         AutomationTracks::iterator i = _automation_tracks.find(param);
2221         if (i != _automation_tracks.end()) {
2222                 return i->second;
2223         } else {
2224                 return boost::shared_ptr<AutomationTimeAxisView>();
2225         }
2226 }
2227
2228 void
2229 RouteTimeAxisView::fast_update ()
2230 {
2231         gm.get_level_meter().update_meters ();
2232 }
2233
2234 void
2235 RouteTimeAxisView::hide_meter ()
2236 {
2237         clear_meter ();
2238         gm.get_level_meter().hide_meters ();
2239 }
2240
2241 void
2242 RouteTimeAxisView::show_meter ()
2243 {
2244         reset_meter ();
2245 }
2246
2247 void
2248 RouteTimeAxisView::reset_meter ()
2249 {
2250         if (Config->get_show_track_meters()) {
2251                 gm.get_level_meter().setup_meters (height-5);
2252         } else {
2253                 hide_meter ();
2254         }
2255 }
2256
2257 void
2258 RouteTimeAxisView::clear_meter ()
2259 {
2260         gm.get_level_meter().clear_meters ();
2261 }
2262
2263 void
2264 RouteTimeAxisView::meter_changed ()
2265 {
2266         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2267         reset_meter();
2268 }
2269
2270 void
2271 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2272 {
2273         reset_meter ();
2274 }
2275
2276 void
2277 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2278 {
2279         using namespace Menu_Helpers;
2280
2281         if (!_underlay_streams.empty()) {
2282                 MenuList& parent_items = parent_menu->items();
2283                 Menu* gs_menu = manage (new Menu);
2284                 gs_menu->set_name ("ArdourContextMenu");
2285                 MenuList& gs_items = gs_menu->items();
2286
2287                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2288
2289                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2290                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2291                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2292                 }
2293         }
2294 }
2295
2296 bool
2297 RouteTimeAxisView::set_underlay_state()
2298 {
2299         if (!underlay_xml_node) {
2300                 return false;
2301         }
2302
2303         XMLNodeList nlist = underlay_xml_node->children();
2304         XMLNodeConstIterator niter;
2305         XMLNode *child_node;
2306
2307         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2308                 child_node = *niter;
2309
2310                 if (child_node->name() != "Underlay") {
2311                         continue;
2312                 }
2313
2314                 XMLProperty* prop = child_node->property ("id");
2315                 if (prop) {
2316                         PBD::ID id (prop->value());
2317
2318                         RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2319
2320                         if (v) {
2321                                 add_underlay(v->view(), false);
2322                         }
2323                 }
2324         }
2325
2326         return false;
2327 }
2328
2329 void
2330 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2331 {
2332         if (!v) {
2333                 return;
2334         }
2335
2336         RouteTimeAxisView& other = v->trackview();
2337
2338         if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2339                 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2340                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2341                         /*NOTREACHED*/
2342                 }
2343
2344                 _underlay_streams.push_back(v);
2345                 other._underlay_mirrors.push_back(this);
2346
2347                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2348
2349 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2350                 if (update_xml) {
2351                         if (!underlay_xml_node) {
2352                                 underlay_xml_node = xml_node->add_child("Underlays");
2353                         }
2354
2355                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2356                         XMLProperty* prop = node->add_property("id");
2357                         prop->set_value(v->trackview().route()->id().to_s());
2358                 }
2359 #endif
2360         }
2361 }
2362
2363 void
2364 RouteTimeAxisView::remove_underlay (StreamView* v)
2365 {
2366         if (!v) {
2367                 return;
2368         }
2369
2370         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2371         RouteTimeAxisView& other = v->trackview();
2372
2373         if (it != _underlay_streams.end()) {
2374                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2375
2376                 if (gm == other._underlay_mirrors.end()) {
2377                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2378                         /*NOTREACHED*/
2379                 }
2380
2381                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2382
2383                 _underlay_streams.erase(it);
2384                 other._underlay_mirrors.erase(gm);
2385
2386                 if (underlay_xml_node) {
2387                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2388                 }
2389         }
2390 }
2391
2392 void
2393 RouteTimeAxisView::set_button_names ()
2394 {
2395         if (_route && _route->solo_safe()) {
2396                 solo_button->remove ();
2397                 if (solo_safe_pixbuf == 0) {
2398                         solo_safe_pixbuf = ::get_icon("solo-safe-icon");
2399                 }
2400                 solo_button->set_image (solo_safe_pixbuf);
2401                 solo_button->set_text (string());
2402         } else {
2403                 solo_button->set_image (Glib::RefPtr<Gdk::Pixbuf>());
2404                 if (Config->get_solo_control_is_listen_control()) {
2405                         switch (Config->get_listen_position()) {
2406                         case AfterFaderListen:
2407                                 solo_button->set_text (_("A"));
2408                                 ARDOUR_UI::instance()->set_tip (*solo_button, _("After-fade listen (AFL)"));
2409                                 break;
2410                         case PreFaderListen:
2411                                 solo_button->set_text (_("P"));
2412                                 ARDOUR_UI::instance()->set_tip (*solo_button, _("Pre-fade listen (PFL)"));
2413                                 break;
2414                         }
2415                 } else {
2416                         solo_button->set_text (_("s"));
2417                         ARDOUR_UI::instance()->set_tip (*solo_button, _("Solo"));
2418                 }
2419         }
2420         mute_button->set_text (_("m"));
2421 }
2422
2423 Gtk::CheckMenuItem*
2424 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2425 {
2426         ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2427         if (i != _main_automation_menu_map.end()) {
2428                 return i->second;
2429         }
2430
2431         i = _subplugin_menu_map.find (param);
2432         if (i != _subplugin_menu_map.end()) {
2433                 return i->second;
2434         }
2435
2436         return 0;
2437 }
2438
2439 void
2440 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2441 {
2442         boost::shared_ptr<AutomationControl> c = _route->gain_control();
2443         if (!c) {
2444                 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2445                 return;
2446         }
2447
2448         gain_track.reset (new AutomationTimeAxisView (_session,
2449                                                       _route, _route->amp(), c, param,
2450                                                       _editor,
2451                                                       *this,
2452                                                       false,
2453                                                       parent_canvas,
2454                                                       _route->amp()->describe_parameter(param)));
2455
2456         if (_view) {
2457                 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2458         }
2459
2460         add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2461 }
2462
2463 static
2464 void add_region_to_list (RegionView* rv, RegionList* l)
2465 {
2466         l->push_back (rv->region());
2467 }
2468
2469 RegionView*
2470 RouteTimeAxisView::combine_regions ()
2471 {
2472         /* as of may 2011, we do not offer uncombine for MIDI tracks
2473          */
2474
2475         if (!is_audio_track()) {
2476                 return 0;
2477         }
2478
2479         if (!_view) {
2480                 return 0;
2481         }
2482
2483         RegionList selected_regions;
2484         boost::shared_ptr<Playlist> playlist = track()->playlist();
2485
2486         _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2487
2488         if (selected_regions.size() < 2) {
2489                 return 0;
2490         }
2491
2492         playlist->clear_changes ();
2493         boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2494
2495         _session->add_command (new StatefulDiffCommand (playlist));
2496         /* make the new region be selected */
2497
2498         return _view->find_view (compound_region);
2499 }
2500
2501 void
2502 RouteTimeAxisView::uncombine_regions ()
2503 {
2504         /* as of may 2011, we do not offer uncombine for MIDI tracks
2505          */
2506         if (!is_audio_track()) {
2507                 return;
2508         }
2509
2510         if (!_view) {
2511                 return;
2512         }
2513
2514         RegionList selected_regions;
2515         boost::shared_ptr<Playlist> playlist = track()->playlist();
2516
2517         /* have to grab selected regions first because the uncombine is going
2518          * to change that in the middle of the list traverse
2519          */
2520
2521         _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2522
2523         playlist->clear_changes ();
2524
2525         for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2526                 playlist->uncombine (*i);
2527         }
2528
2529         _session->add_command (new StatefulDiffCommand (playlist));
2530 }
2531
2532 string
2533 RouteTimeAxisView::state_id() const
2534 {
2535         return string_compose ("rtav %1", _route->id().to_s());
2536 }
2537
2538
2539 void
2540 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2541 {
2542         TimeAxisView::remove_child (c);
2543         
2544         boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2545         if (a) {
2546                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2547                         if (i->second == a) {
2548                                 _automation_tracks.erase (i);
2549                                 return;
2550                         }
2551                 }
2552         }
2553 }