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