Re-work layering in possibly debatable ways. Sketchy docs in doc/layering.
[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/audioplaylist.h"
47 #include "ardour/diskstream.h"
48 #include "ardour/event_type_map.h"
49 #include "ardour/ladspa_plugin.h"
50 #include "ardour/location.h"
51 #include "ardour/panner.h"
52 #include "ardour/playlist.h"
53 #include "ardour/playlist.h"
54 #include "ardour/processor.h"
55 #include "ardour/profile.h"
56 #include "ardour/region_factory.h"
57 #include "ardour/route_group.h"
58 #include "ardour/session.h"
59 #include "ardour/session_playlist.h"
60 #include "ardour/debug.h"
61 #include "ardour/utils.h"
62 #include "evoral/Parameter.hpp"
63
64 #include "ardour_ui.h"
65 #include "ardour_button.h"
66 #include "debug.h"
67 #include "global_signals.h"
68 #include "route_time_axis.h"
69 #include "automation_time_axis.h"
70 #include "canvas_impl.h"
71 #include "crossfade_view.h"
72 #include "enums.h"
73 #include "gui_thread.h"
74 #include "keyboard.h"
75 #include "playlist_selector.h"
76 #include "point_selection.h"
77 #include "prompter.h"
78 #include "public_editor.h"
79 #include "region_view.h"
80 #include "rgb_macros.h"
81 #include "selection.h"
82 #include "simplerect.h"
83 #include "streamview.h"
84 #include "utils.h"
85 #include "route_group_menu.h"
86
87 #include "ardour/track.h"
88
89 #include "i18n.h"
90
91 using namespace ARDOUR;
92 using namespace PBD;
93 using namespace Gtkmm2ext;
94 using namespace Gtk;
95 using namespace Editing;
96 using namespace std;
97 using std::list;
98
99 Glib::RefPtr<Gdk::Pixbuf> RouteTimeAxisView::slider;
100
101 void
102 RouteTimeAxisView::setup_slider_pix ()
103 {
104         if ((slider = ::get_icon ("fader_belt_h")) == 0) {
105                 throw failed_constructor ();
106         }
107 }
108
109 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
110         : AxisView(sess)
111         , RouteUI(sess)
112         , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
113         , _view (0)
114         , parent_canvas (canvas)
115         , no_redraw (false)
116         , button_table (3, 3)
117         , route_group_button (_("g"))
118         , playlist_button (_("p"))
119         , automation_button (_("a"))
120         , automation_action_menu (0)
121         , plugins_submenu_item (0)
122         , route_group_menu (0)
123         , playlist_action_menu (0)
124         , mode_menu (0)
125         , color_mode_menu (0)
126         , gm (sess, slider, true, 115)
127 {
128 }
129
130 void
131 RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
132 {
133         RouteUI::set_route (rt);
134         
135         gm.set_controls (_route, _route->shared_peak_meter(), _route->amp());
136         gm.get_level_meter().set_no_show_all();
137         gm.get_level_meter().setup_meters(50);
138
139         string str = gui_property ("height");
140         if (!str.empty()) {
141                 set_height (atoi (str));
142         } else {
143                 set_height (preset_height (HeightNormal));
144         }
145
146         if (!_route->is_hidden()) {
147                 if (gui_property ("visible").empty()) {
148                         set_gui_property ("visible", true);
149                 }
150         } else {
151                 set_gui_property ("visible", false);
152         }
153
154         mute_changed (0);
155         update_solo_display ();
156
157         timestretch_rect = 0;
158         no_redraw = false;
159
160         ignore_toggle = false;
161
162         route_group_button.set_name ("route button");
163         playlist_button.set_name ("route button");
164         automation_button.set_name ("route button");
165
166         route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false);
167         playlist_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click));
168         automation_button.signal_clicked.connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click));
169
170         if (is_track()) {
171
172                 /* use icon */
173                 
174                 switch (track()->mode()) {
175                 case ARDOUR::Normal:
176                 case ARDOUR::NonLayered:
177                         rec_enable_button->set_image (::get_icon (X_("record_normal_red")));
178                         break;
179                 case ARDOUR::Destructive:
180                         rec_enable_button->set_image (::get_icon (X_("record_tape_red")));
181                         break;
182                 }
183
184                 controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
185
186                 if (is_midi_track()) {
187                         ARDOUR_UI::instance()->set_tip(*rec_enable_button, _("Record (Right-click for Step Edit)"));
188                 } else {
189                         ARDOUR_UI::instance()->set_tip(*rec_enable_button, _("Record"));
190                 }
191
192                 rec_enable_button->set_sensitive (_session->writable());
193         }
194         
195         controls_hbox.pack_start(gm.get_level_meter(), false, false);
196         _route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
197         _route->input()->changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
198         _route->output()->changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
199
200         controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
201
202         if (!_route->is_master()) {
203                 controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
204         }
205
206         controls_table.attach (route_group_button, 7, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
207         controls_table.attach (gm.get_gain_slider(), 0, 5, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
208
209         ARDOUR_UI::instance()->set_tip(*solo_button,_("Solo"));
210         ARDOUR_UI::instance()->set_tip(*mute_button,_("Mute"));
211         ARDOUR_UI::instance()->set_tip(route_group_button, _("Route Group"));
212         ARDOUR_UI::instance()->set_tip(playlist_button,_("Playlist"));
213         ARDOUR_UI::instance()->set_tip(automation_button, _("Automation"));
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), ui_bind (&RouteTimeAxisView::processors_changed, this, _1), gui_context());
226         _route->PropertyChanged.connect (*this, invalidator (*this), ui_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                 route_group_menu->detach ();
666
667                 WeakRouteList r;
668                 for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
669                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
670                         if (rtv) {
671                                 r.push_back (rtv->route ());
672                         }
673                 }
674
675                 if (r.empty ()) {
676                         r.push_back (route ());
677                 }
678
679                 route_group_menu->build (r);
680                 items.push_back (MenuElem (_("Route Group"), *route_group_menu->menu ()));
681
682                 build_automation_action_menu (true);
683                 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
684
685                 items.push_back (SeparatorElem());
686         }
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)
767 {
768         double x1;
769         double x2;
770         double y2;
771
772         TimeAxisView::show_timestretch (start, end);
773
774         hide_timestretch ();
775
776 #if 0
777         if (ts.empty()) {
778                 return;
779         }
780
781
782         /* check that the time selection was made in our route, or our route group.
783            remember that route_group() == 0 implies the route is *not* in a edit group.
784         */
785
786         if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
787                 /* this doesn't apply to us */
788                 return;
789         }
790
791         /* ignore it if our edit group is not active */
792
793         if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
794                 return;
795         }
796 #endif
797
798         if (timestretch_rect == 0) {
799                 timestretch_rect = new SimpleRect (*canvas_display ());
800                 timestretch_rect->property_x1() =  0.0;
801                 timestretch_rect->property_y1() =  0.0;
802                 timestretch_rect->property_x2() =  0.0;
803                 timestretch_rect->property_y2() =  0.0;
804                 timestretch_rect->property_fill_color_rgba() =  ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
805                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
806         }
807
808         timestretch_rect->show ();
809         timestretch_rect->raise_to_top ();
810
811         x1 = start / _editor.get_current_zoom();
812         x2 = (end - 1) / _editor.get_current_zoom();
813         y2 = current_height() - 2;
814
815         timestretch_rect->property_x1() = x1;
816         timestretch_rect->property_y1() = 1.0;
817         timestretch_rect->property_x2() = x2;
818         timestretch_rect->property_y2() = y2;
819 }
820
821 void
822 RouteTimeAxisView::hide_timestretch ()
823 {
824         TimeAxisView::hide_timestretch ();
825
826         if (timestretch_rect) {
827                 timestretch_rect->hide ();
828         }
829 }
830
831 void
832 RouteTimeAxisView::show_selection (TimeSelection& ts)
833 {
834
835 #if 0
836         /* ignore it if our edit group is not active or if the selection was started
837            in some other track or route group (remember that route_group() == 0 means
838            that the track is not in an route group).
839         */
840
841         if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
842             (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
843                 hide_selection ();
844                 return;
845         }
846 #endif
847
848         TimeAxisView::show_selection (ts);
849 }
850
851 void
852 RouteTimeAxisView::set_height (uint32_t h)
853 {
854         int gmlen = h - 5;
855         bool height_changed = (height == 0) || (h != height);
856         gm.get_level_meter().setup_meters (gmlen);
857
858         TimeAxisView::set_height (h);
859
860         if (_view) {
861                 _view->set_height ((double) current_height());
862         }
863
864         if (height >= preset_height (HeightNormal)) {
865
866                 reset_meter();
867
868                 gm.get_gain_slider().show();
869                 mute_button->show();
870                 if (!_route || _route->is_monitor()) {
871                         solo_button->hide();
872                 } else {
873                         solo_button->show();
874                 }
875                 if (rec_enable_button)
876                         rec_enable_button->show();
877
878                 route_group_button.show();
879                 automation_button.show();
880
881                 if (is_track() && track()->mode() == ARDOUR::Normal) {
882                         playlist_button.show();
883                 }
884
885         } else {
886
887                 reset_meter();
888
889                 gm.get_gain_slider().hide();
890                 mute_button->show();
891                 if (!_route || _route->is_monitor()) {
892                         solo_button->hide();
893                 } else {
894                         solo_button->show();
895                 }
896                 if (rec_enable_button)
897                         rec_enable_button->show();
898
899                 route_group_button.hide ();
900                 automation_button.hide ();
901
902                 if (is_track() && track()->mode() == ARDOUR::Normal) {
903                         playlist_button.hide ();
904                 }
905
906         }
907
908         if (height_changed && !no_redraw) {
909                 /* only emit the signal if the height really changed */
910                 request_redraw ();
911         }
912 }
913
914 void
915 RouteTimeAxisView::route_color_changed ()
916 {
917         if (_view) {
918                 _view->apply_color (color(), StreamView::RegionColor);
919         }
920 }
921
922 void
923 RouteTimeAxisView::reset_samples_per_unit ()
924 {
925         set_samples_per_unit (_editor.get_current_zoom());
926 }
927
928 void
929 RouteTimeAxisView::horizontal_position_changed ()
930 {
931         if (_view) {
932                 _view->horizontal_position_changed ();
933         }
934 }
935
936 void
937 RouteTimeAxisView::set_samples_per_unit (double spu)
938 {
939         double speed = 1.0;
940
941         if (track()) {
942                 speed = track()->speed();
943         }
944
945         if (_view) {
946                 _view->set_samples_per_unit (spu * speed);
947         }
948
949         TimeAxisView::set_samples_per_unit (spu * speed);
950 }
951
952 void
953 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
954 {
955         if (!mitem->get_active()) {
956                 /* this is one of the two calls made when these radio menu items change status. this one
957                    is for the item that became inactive, and we want to ignore it.
958                 */
959                 return;
960         }
961
962         if (apply_to_selection) {
963                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
964         } else {
965                 if (track ()) {
966                         track()->set_align_choice (choice);
967                 }
968         }
969 }
970
971 void
972 RouteTimeAxisView::rename_current_playlist ()
973 {
974         ArdourPrompter prompter (true);
975         string name;
976
977         boost::shared_ptr<Track> tr = track();
978         if (!tr || tr->destructive()) {
979                 return;
980         }
981
982         boost::shared_ptr<Playlist> pl = tr->playlist();
983         if (!pl) {
984                 return;
985         }
986
987         prompter.set_title (_("Rename Playlist"));
988         prompter.set_prompt (_("New name for playlist:"));
989         prompter.set_initial_text (pl->name());
990         prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
991         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
992
993         switch (prompter.run ()) {
994         case Gtk::RESPONSE_ACCEPT:
995                 prompter.get_result (name);
996                 if (name.length()) {
997                         pl->set_name (name);
998                 }
999                 break;
1000
1001         default:
1002                 break;
1003         }
1004 }
1005
1006 std::string
1007 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1008 {
1009         std::string ret (basename);
1010
1011         std::string const group_string = "." + route_group()->name() + ".";
1012
1013         // iterate through all playlists
1014         int maxnumber = 0;
1015         for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1016                 std::string tmp = (*i)->name();
1017
1018                 std::string::size_type idx = tmp.find(group_string);
1019                 // find those which belong to this group
1020                 if (idx != string::npos) {
1021                         tmp = tmp.substr(idx + group_string.length());
1022
1023                         // and find the largest current number
1024                         int x = atoi(tmp.c_str());
1025                         if (x > maxnumber) {
1026                                 maxnumber = x;
1027                         }
1028                 }
1029         }
1030
1031         maxnumber++;
1032
1033         char buf[32];
1034         snprintf (buf, sizeof(buf), "%d", maxnumber);
1035
1036         ret = this->name() + "." + route_group()->name () + "." + buf;
1037
1038         return ret;
1039 }
1040
1041 void
1042 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1043 {
1044         string name;
1045
1046         boost::shared_ptr<Track> tr = track ();
1047         if (!tr || tr->destructive()) {
1048                 return;
1049         }
1050
1051         boost::shared_ptr<const Playlist> pl = tr->playlist();
1052         if (!pl) {
1053                 return;
1054         }
1055
1056         name = pl->name();
1057
1058         if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) {
1059                 name = resolve_new_group_playlist_name(name, playlists_before_op);
1060         }
1061
1062         while (_session->playlists->by_name(name)) {
1063                 name = Playlist::bump_name (name, *_session);
1064         }
1065
1066         // TODO: The prompter "new" button should be de-activated if the user
1067         // specifies a playlist name which already exists in the session.
1068
1069         if (prompt) {
1070
1071                 ArdourPrompter prompter (true);
1072
1073                 prompter.set_title (_("New Copy Playlist"));
1074                 prompter.set_prompt (_("Name for new playlist:"));
1075                 prompter.set_initial_text (name);
1076                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1077                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1078                 prompter.show_all ();
1079
1080                 switch (prompter.run ()) {
1081                 case Gtk::RESPONSE_ACCEPT:
1082                         prompter.get_result (name);
1083                         break;
1084
1085                 default:
1086                         return;
1087                 }
1088         }
1089
1090         if (name.length()) {
1091                 tr->use_copy_playlist ();
1092                 tr->playlist()->set_name (name);
1093         }
1094 }
1095
1096 void
1097 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1098 {
1099         string name;
1100
1101         boost::shared_ptr<Track> tr = track ();
1102         if (!tr || tr->destructive()) {
1103                 return;
1104         }
1105
1106         boost::shared_ptr<const Playlist> pl = tr->playlist();
1107         if (!pl) {
1108                 return;
1109         }
1110
1111         name = pl->name();
1112
1113         if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) {
1114                 name = resolve_new_group_playlist_name(name,playlists_before_op);
1115         }
1116
1117         while (_session->playlists->by_name(name)) {
1118                 name = Playlist::bump_name (name, *_session);
1119         }
1120
1121
1122         if (prompt) {
1123
1124                 ArdourPrompter prompter (true);
1125
1126                 prompter.set_title (_("New Playlist"));
1127                 prompter.set_prompt (_("Name for new playlist:"));
1128                 prompter.set_initial_text (name);
1129                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1130                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1131
1132                 switch (prompter.run ()) {
1133                 case Gtk::RESPONSE_ACCEPT:
1134                         prompter.get_result (name);
1135                         break;
1136
1137                 default:
1138                         return;
1139                 }
1140         }
1141
1142         if (name.length()) {
1143                 tr->use_new_playlist ();
1144                 tr->playlist()->set_name (name);
1145         }
1146 }
1147
1148 void
1149 RouteTimeAxisView::clear_playlist ()
1150 {
1151         boost::shared_ptr<Track> tr = track ();
1152         if (!tr || tr->destructive()) {
1153                 return;
1154         }
1155
1156         boost::shared_ptr<Playlist> pl = tr->playlist();
1157         if (!pl) {
1158                 return;
1159         }
1160
1161         _editor.clear_playlist (pl);
1162 }
1163
1164 void
1165 RouteTimeAxisView::speed_changed ()
1166 {
1167         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_unit, this));
1168 }
1169
1170 void
1171 RouteTimeAxisView::update_diskstream_display ()
1172 {
1173         if (!track()) {
1174                 return;
1175         }
1176
1177         map_frozen ();
1178 }
1179
1180 void
1181 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1182 {
1183         if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1184
1185                 /* special case: select/deselect all tracks */
1186                 if (_editor.get_selection().selected (this)) {
1187                         _editor.get_selection().clear_tracks ();
1188                 } else {
1189                         _editor.select_all_tracks ();
1190                 }
1191
1192                 return;
1193         }
1194
1195         switch (ArdourKeyboard::selection_type (ev->state)) {
1196         case Selection::Toggle:
1197                 _editor.get_selection().toggle (this);
1198                 break;
1199
1200         case Selection::Set:
1201                 _editor.get_selection().set (this);
1202                 break;
1203
1204         case Selection::Extend:
1205                 _editor.extend_selection_to_track (*this);
1206                 break;
1207
1208         case Selection::Add:
1209                 _editor.get_selection().add (this);
1210                 break;
1211         }
1212 }
1213
1214 void
1215 RouteTimeAxisView::set_selected_points (PointSelection& points)
1216 {
1217         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1218                 (*i)->set_selected_points (points);
1219         }
1220 }
1221
1222 void
1223 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1224 {
1225         if (_view) {
1226                 _view->set_selected_regionviews (regions);
1227         }
1228 }
1229
1230 /** Add the selectable things that we have to a list.
1231  * @param results List to add things to.
1232  */
1233 void
1234 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
1235 {
1236         double speed = 1.0;
1237
1238         if (track() != 0) {
1239                 speed = track()->speed();
1240         }
1241
1242         framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1243         framepos_t const end_adjusted   = session_frame_to_track_frame(end, speed);
1244
1245         if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1246                 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1247         }
1248
1249         /* pick up visible automation tracks */
1250
1251         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1252                 if (!(*i)->hidden()) {
1253                         (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1254                 }
1255         }
1256 }
1257
1258 void
1259 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1260 {
1261         if (_view) {
1262                 _view->get_inverted_selectables (sel, results);
1263         }
1264
1265         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1266                 if (!(*i)->hidden()) {
1267                         (*i)->get_inverted_selectables (sel, results);
1268                 }
1269         }
1270
1271         return;
1272 }
1273
1274 RouteGroup*
1275 RouteTimeAxisView::route_group () const
1276 {
1277         return _route->route_group();
1278 }
1279
1280 string
1281 RouteTimeAxisView::name() const
1282 {
1283         return _route->name();
1284 }
1285
1286 boost::shared_ptr<Playlist>
1287 RouteTimeAxisView::playlist () const
1288 {
1289         boost::shared_ptr<Track> tr;
1290
1291         if ((tr = track()) != 0) {
1292                 return tr->playlist();
1293         } else {
1294                 return boost::shared_ptr<Playlist> ();
1295         }
1296 }
1297
1298 void
1299 RouteTimeAxisView::name_entry_changed ()
1300 {
1301         string x = name_entry.get_text ();
1302
1303         if (x == _route->name()) {
1304                 return;
1305         }
1306
1307         strip_whitespace_edges (x);
1308
1309         if (x.length() == 0) {
1310                 name_entry.set_text (_route->name());
1311                 return;
1312         }
1313
1314         if (_session->route_name_internal (x)) {
1315                 ARDOUR_UI::instance()->popup_error (string_compose (_("You cannot create a track with that name as it is reserved for %1"),
1316                                                                     PROGRAM_NAME));
1317                 name_entry.grab_focus ();
1318         } else if (RouteUI::verify_new_route_name (x)) {
1319                 _route->set_name (x);
1320         } else {
1321                 name_entry.grab_focus ();
1322         }
1323 }
1324
1325 boost::shared_ptr<Region>
1326 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1327 {
1328         boost::shared_ptr<Playlist> pl = playlist ();
1329
1330         if (pl) {
1331                 return pl->find_next_region (pos, point, dir);
1332         }
1333
1334         return boost::shared_ptr<Region> ();
1335 }
1336
1337 framepos_t
1338 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1339 {
1340         boost::shared_ptr<Playlist> pl = playlist ();
1341
1342         if (pl) {
1343                 return pl->find_next_region_boundary (pos, dir);
1344         }
1345
1346         return -1;
1347 }
1348
1349 void
1350 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1351 {
1352         boost::shared_ptr<Playlist> what_we_got;
1353         boost::shared_ptr<Track> tr = track ();
1354         boost::shared_ptr<Playlist> playlist;
1355
1356         if (tr == 0) {
1357                 /* route is a bus, not a track */
1358                 return;
1359         }
1360
1361         playlist = tr->playlist();
1362
1363         TimeSelection time (selection.time);
1364         float const speed = tr->speed();
1365         if (speed != 1.0f) {
1366                 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1367                         (*i).start = session_frame_to_track_frame((*i).start, speed);
1368                         (*i).end   = session_frame_to_track_frame((*i).end,   speed);
1369                 }
1370         }
1371
1372         playlist->clear_changes ();
1373         playlist->clear_owned_changes ();
1374
1375         switch (op) {
1376         case Delete:
1377                 if (playlist->cut (time) != 0) {
1378                         vector<Command*> cmds;
1379                         playlist->rdiff (cmds);
1380                         _session->add_commands (cmds);
1381                         
1382                         _session->add_command (new StatefulDiffCommand (playlist));
1383                 }
1384                 break;
1385                 
1386         case Cut:
1387                 if ((what_we_got = playlist->cut (time)) != 0) {
1388                         _editor.get_cut_buffer().add (what_we_got);
1389                         vector<Command*> cmds;
1390                         playlist->rdiff (cmds);
1391                         _session->add_commands (cmds);
1392
1393                         _session->add_command (new StatefulDiffCommand (playlist));
1394                 }
1395                 break;
1396         case Copy:
1397                 if ((what_we_got = playlist->copy (time)) != 0) {
1398                         _editor.get_cut_buffer().add (what_we_got);
1399                 }
1400                 break;
1401
1402         case Clear:
1403                 if ((what_we_got = playlist->cut (time)) != 0) {
1404
1405                         vector<Command*> cmds;
1406                         playlist->rdiff (cmds);
1407                         _session->add_commands (cmds);
1408                         _session->add_command (new StatefulDiffCommand (playlist));
1409                         what_we_got->release ();
1410                 }
1411                 break;
1412         }
1413 }
1414
1415 bool
1416 RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
1417 {
1418         if (!is_track()) {
1419                 return false;
1420         }
1421
1422         boost::shared_ptr<Playlist> pl = playlist ();
1423         PlaylistSelection::iterator p;
1424
1425         for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth) {}
1426
1427         if (p == selection.playlists.end()) {
1428                 return false;
1429         }
1430
1431         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1432
1433         if (track()->speed() != 1.0f) {
1434                 pos = session_frame_to_track_frame (pos, track()->speed());
1435                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1436         }
1437
1438         pl->clear_changes ();
1439         pl->paste (*p, pos, times);
1440         _session->add_command (new StatefulDiffCommand (pl));
1441
1442         return true;
1443 }
1444
1445
1446 struct PlaylistSorter {
1447     bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1448             return a->sort_id() < b->sort_id();
1449     }
1450 };
1451
1452 void
1453 RouteTimeAxisView::build_playlist_menu ()
1454 {
1455         using namespace Menu_Helpers;
1456
1457         if (!is_track()) {
1458                 return;
1459         }
1460
1461         delete playlist_action_menu;
1462         playlist_action_menu = new Menu;
1463         playlist_action_menu->set_name ("ArdourContextMenu");
1464
1465         MenuList& playlist_items = playlist_action_menu->items();
1466         playlist_action_menu->set_name ("ArdourContextMenu");
1467         playlist_items.clear();
1468
1469         RadioMenuItem::Group playlist_group;
1470         boost::shared_ptr<Track> tr = track ();
1471
1472         vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1473
1474         /* sort the playlists */
1475         PlaylistSorter cmp;
1476         sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1477
1478         /* add the playlists to the menu */
1479         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1480                 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1481                 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1482                 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1483
1484                 if (tr->playlist()->id() == (*i)->id()) {
1485                         item->set_active();
1486
1487                 }
1488         }
1489
1490         playlist_items.push_back (SeparatorElem());
1491         playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1492         playlist_items.push_back (SeparatorElem());
1493
1494         if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) {
1495                 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1496                 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1497
1498         } else {
1499                 // Use a label which tells the user what is happening
1500                 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1501                 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1502
1503         }
1504
1505         playlist_items.push_back (SeparatorElem());
1506         playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1507         playlist_items.push_back (SeparatorElem());
1508
1509         playlist_items.push_back (MenuElem(_("Select From All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1510 }
1511
1512 void
1513 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1514 {
1515         assert (is_track());
1516
1517         // exit if we were triggered by deactivating the old playlist
1518         if (!item->get_active()) {
1519                 return;
1520         }
1521
1522         boost::shared_ptr<Playlist> pl (wpl.lock());
1523
1524         if (!pl) {
1525                 return;
1526         }
1527
1528         if (track()->playlist() == pl) {
1529                 // exit when use_playlist is called by the creation of the playlist menu
1530                 // or the playlist choice is unchanged
1531                 return;
1532         }
1533
1534         track()->use_playlist (pl);
1535         
1536         RouteGroup* rg = route_group();
1537         
1538         if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::edit.property_id)) {
1539                 std::string group_string = "." + rg->name() + ".";
1540                 
1541                 std::string take_name = pl->name();
1542                 std::string::size_type idx = take_name.find(group_string);
1543                 
1544                 if (idx == std::string::npos)
1545                         return;
1546                 
1547                 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1548                 
1549                 boost::shared_ptr<RouteList> rl (rg->route_list());
1550                 
1551                 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1552                         if ( (*i) == this->route()) {
1553                                 continue;
1554                         }
1555                         
1556                         std::string playlist_name = (*i)->name()+group_string+take_name;
1557                         
1558                         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1559                         if (!track) {
1560                                 continue;
1561                         }
1562                         
1563                         boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1564                         if (!ipl) {
1565                                 // No playlist for this track for this take yet, make it
1566                                 track->use_new_playlist();
1567                                 track->playlist()->set_name(playlist_name);
1568                         } else {
1569                                 track->use_playlist(ipl);
1570                         }
1571                 }
1572         }
1573 }
1574
1575 void
1576 RouteTimeAxisView::show_playlist_selector ()
1577 {
1578         _editor.playlist_selector().show_for (this);
1579 }
1580
1581 void
1582 RouteTimeAxisView::map_frozen ()
1583 {
1584         if (!is_track()) {
1585                 return;
1586         }
1587
1588         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1589
1590         switch (track()->freeze_state()) {
1591         case Track::Frozen:
1592                 playlist_button.set_sensitive (false);
1593                 rec_enable_button->set_sensitive (false);
1594                 break;
1595         default:
1596                 playlist_button.set_sensitive (true);
1597                 rec_enable_button->set_sensitive (true);
1598                 break;
1599         }
1600 }
1601
1602 void
1603 RouteTimeAxisView::color_handler ()
1604 {
1605         //case cTimeStretchOutline:
1606         if (timestretch_rect) {
1607                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
1608         }
1609         //case cTimeStretchFill:
1610         if (timestretch_rect) {
1611                 timestretch_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
1612         }
1613
1614         reset_meter();
1615 }
1616
1617 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1618  *  Will add track if necessary.
1619  */
1620 void
1621 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1622 {
1623         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1624         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1625
1626         if (!track) {
1627                 /* it doesn't exist yet, so we don't care about the button state: just add it */
1628                 create_automation_child (param, true);
1629         } else {
1630                 assert (menu);
1631                 bool yn = menu->get_active();
1632                 bool changed = false;
1633
1634                 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1635
1636                         /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1637                            will have done that for us.
1638                         */
1639
1640                         if (changed && !no_redraw) {
1641                                 request_redraw ();
1642                         }
1643                 }
1644         }
1645 }
1646
1647 void
1648 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1649 {
1650         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1651
1652         if (!track) {
1653                 return;
1654         }
1655
1656         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1657
1658         if (menu && !_hidden) {
1659                 ignore_toggle = true;
1660                 menu->set_active (false);
1661                 ignore_toggle = false;
1662         }
1663
1664         if (_route && !no_redraw) {
1665                 request_redraw ();
1666         }
1667 }
1668
1669
1670 void
1671 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
1672 {
1673         if (apply_to_selection) {
1674                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
1675         } else {
1676                 no_redraw = true;
1677
1678                 /* Show our automation */
1679
1680                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1681                         i->second->set_marked_for_display (true);
1682
1683                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1684
1685                         if (menu) {
1686                                 menu->set_active(true);
1687                         }
1688                 }
1689
1690
1691                 /* Show processor automation */
1692
1693                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1694                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1695                                 if ((*ii)->view == 0) {
1696                                         add_processor_automation_curve ((*i)->processor, (*ii)->what);
1697                                 }
1698
1699                                 (*ii)->menu_item->set_active (true);
1700                         }
1701                 }
1702
1703                 no_redraw = false;
1704
1705                 /* Redraw */
1706
1707                 request_redraw ();
1708         }
1709 }
1710
1711 void
1712 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
1713 {
1714         if (apply_to_selection) {
1715                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
1716         } else {
1717                 no_redraw = true;
1718
1719                 /* Show our automation */
1720
1721                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1722                         if (i->second->has_automation()) {
1723                                 i->second->set_marked_for_display (true);
1724
1725                                 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1726                                 if (menu) {
1727                                         menu->set_active(true);
1728                                 }
1729                         }
1730                 }
1731
1732                 /* Show processor automation */
1733
1734                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1735                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1736                                 if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
1737                                         (*ii)->menu_item->set_active (true);
1738                                 }
1739                         }
1740                 }
1741
1742                 no_redraw = false;
1743
1744                 request_redraw ();
1745         }
1746 }
1747
1748 void
1749 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
1750 {
1751         if (apply_to_selection) {
1752                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
1753         } else {
1754                 no_redraw = true;
1755
1756                 /* Hide our automation */
1757
1758                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1759                         i->second->set_marked_for_display (false);
1760
1761                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1762
1763                         if (menu) {
1764                                 menu->set_active (false);
1765                         }
1766                 }
1767
1768                 /* Hide processor automation */
1769
1770                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1771                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1772                                 (*ii)->menu_item->set_active (false);
1773                         }
1774                 }
1775
1776                 no_redraw = false;
1777                 request_redraw ();
1778         }
1779 }
1780
1781
1782 void
1783 RouteTimeAxisView::region_view_added (RegionView* rv)
1784 {
1785         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
1786         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1787                 boost::shared_ptr<AutomationTimeAxisView> atv;
1788
1789                 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1790                         atv->add_ghost(rv);
1791                 }
1792         }
1793
1794         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
1795                 (*i)->add_ghost(rv);
1796         }
1797 }
1798
1799 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1800 {
1801         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1802                 delete *i;
1803         }
1804 }
1805
1806
1807 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1808 {
1809         parent.remove_processor_automation_node (this);
1810 }
1811
1812 void
1813 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1814 {
1815         if (pan->view) {
1816                 remove_child (pan->view);
1817         }
1818 }
1819
1820 RouteTimeAxisView::ProcessorAutomationNode*
1821 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1822 {
1823         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1824
1825                 if ((*i)->processor == processor) {
1826
1827                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1828                                 if ((*ii)->what == what) {
1829                                         return *ii;
1830                                 }
1831                         }
1832                 }
1833         }
1834
1835         return 0;
1836 }
1837
1838 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
1839 void
1840 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1841 {
1842         string name;
1843         ProcessorAutomationNode* pan;
1844
1845         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1846                 /* session state may never have been saved with new plugin */
1847                 error << _("programming error: ")
1848                       << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
1849                                          processor->name(), what.type(), (int) what.channel(), what.id() )
1850                       << endmsg;
1851                 /*NOTREACHED*/
1852                 return;
1853         }
1854
1855         if (pan->view) {
1856                 return;
1857         }
1858
1859         boost::shared_ptr<AutomationControl> control
1860                 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
1861         
1862         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
1863                 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
1864                                             _editor, *this, false, parent_canvas, 
1865                                             processor->describe_parameter (what), processor->name()));
1866
1867         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
1868
1869         add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
1870
1871         if (_view) {
1872                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
1873         }
1874 }
1875
1876 void
1877 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
1878 {
1879         if (!_hidden) {
1880                 pan->menu_item->set_active (false);
1881         }
1882
1883         if (!no_redraw) {
1884                 request_redraw ();
1885         }
1886 }
1887
1888 void
1889 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
1890 {
1891         boost::shared_ptr<Processor> processor (p.lock ());
1892
1893         if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
1894                 /* The Amp processor is a special case and is dealt with separately */
1895                 return;
1896         }
1897
1898         set<Evoral::Parameter> existing;
1899
1900         processor->what_has_data (existing);
1901
1902         for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
1903                 
1904                 Evoral::Parameter param (*i);
1905                 boost::shared_ptr<AutomationLine> al;
1906
1907                 if ((al = find_processor_automation_curve (processor, param)) != 0) {
1908                         al->queue_reset ();
1909                 } else {
1910                         add_processor_automation_curve (processor, param);
1911                 }
1912         }
1913 }
1914
1915 void
1916 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
1917 {
1918         using namespace Menu_Helpers;
1919
1920         add_child (track);
1921
1922         track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
1923
1924         _automation_tracks[param] = track;
1925
1926         /* existing state overrides "show" argument */
1927         string s = track->gui_property ("visible");
1928         if (!s.empty()) { 
1929                 show = string_is_affirmative (s);
1930         }
1931
1932         /* this might or might not change the visibility status, so don't rely on it */
1933         track->set_marked_for_display (show);
1934
1935         if (show && !no_redraw) {
1936                 request_redraw ();
1937         }
1938
1939         if (!EventTypeMap::instance().is_midi_parameter(param)) {
1940                 /* MIDI-related parameters are always in the menu, there's no
1941                    reason to rebuild the menu just because we added a automation
1942                    lane for one of them. But if we add a non-MIDI automation
1943                    lane, then we need to invalidate the display menu.
1944                 */
1945                 delete display_menu;
1946                 display_menu = 0;
1947         }
1948 }
1949
1950 void
1951 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
1952 {
1953         boost::shared_ptr<Processor> processor (p.lock ());
1954
1955         if (!processor || !processor->display_to_user ()) {
1956                 return;
1957         }
1958
1959         /* we use this override to veto the Amp processor from the plugin menu,
1960            as its automation lane can be accessed using the special "Fader" menu
1961            option
1962         */
1963
1964         if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
1965                 return;
1966         }
1967
1968         using namespace Menu_Helpers;
1969         ProcessorAutomationInfo *rai;
1970         list<ProcessorAutomationInfo*>::iterator x;
1971
1972         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
1973
1974         if (automatable.empty()) {
1975                 return;
1976         }
1977
1978         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
1979                 if ((*x)->processor == processor) {
1980                         break;
1981                 }
1982         }
1983
1984         if (x == processor_automation.end()) {
1985
1986                 rai = new ProcessorAutomationInfo (processor);
1987                 processor_automation.push_back (rai);
1988
1989         } else {
1990
1991                 rai = *x;
1992
1993         }
1994
1995         /* any older menu was deleted at the top of processors_changed()
1996            when we cleared the subplugin menu.
1997         */
1998
1999         rai->menu = manage (new Menu);
2000         MenuList& items = rai->menu->items();
2001         rai->menu->set_name ("ArdourContextMenu");
2002
2003         items.clear ();
2004
2005         std::set<Evoral::Parameter> has_visible_automation;
2006         AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2007
2008         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2009
2010                 ProcessorAutomationNode* pan;
2011                 CheckMenuItem* mitem;
2012
2013                 string name = processor->describe_parameter (*i);
2014
2015                 items.push_back (CheckMenuElem (name));
2016                 mitem = dynamic_cast<CheckMenuItem*> (&items.back());
2017                 
2018                 _subplugin_menu_map[*i] = mitem;
2019
2020                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2021                         mitem->set_active(true);
2022                 }
2023
2024                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2025
2026                         /* new item */
2027
2028                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2029
2030                         rai->lines.push_back (pan);
2031
2032                 } else {
2033
2034                         pan->menu_item = mitem;
2035
2036                 }
2037
2038                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2039         }
2040
2041         /* add the menu for this processor, because the subplugin
2042            menu is always cleared at the top of processors_changed().
2043            this is the result of some poor design in gtkmm and/or
2044            GTK+.
2045         */
2046
2047         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2048         rai->valid = true;
2049 }
2050
2051 void
2052 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2053                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2054 {
2055         bool showit = pan->menu_item->get_active();
2056         bool redraw = false;
2057
2058         if (pan->view == 0 && showit) {
2059                 add_processor_automation_curve (rai->processor, pan->what);
2060                 redraw = true;
2061         }
2062
2063         if (pan->view && pan->view->set_marked_for_display (showit)) {
2064                 redraw = true;
2065         }
2066         
2067         if (redraw && !no_redraw) {
2068                 request_redraw ();
2069         }
2070 }
2071
2072 void
2073 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2074 {
2075         if (c.type == RouteProcessorChange::MeterPointChange) {
2076                 /* nothing to do if only the meter point has changed */
2077                 return;
2078         }
2079
2080         using namespace Menu_Helpers;
2081
2082         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2083                 (*i)->valid = false;
2084         }
2085
2086         setup_processor_menu_and_curves ();
2087
2088         bool deleted_processor_automation = false;
2089
2090         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2091
2092                 list<ProcessorAutomationInfo*>::iterator tmp;
2093
2094                 tmp = i;
2095                 ++tmp;
2096
2097                 if (!(*i)->valid) {
2098
2099                         delete *i;
2100                         processor_automation.erase (i);
2101                         deleted_processor_automation = true;
2102
2103                 }
2104
2105                 i = tmp;
2106         }
2107
2108         if (deleted_processor_automation && !no_redraw) {
2109                 request_redraw ();
2110         }
2111 }
2112
2113 boost::shared_ptr<AutomationLine>
2114 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2115 {
2116         ProcessorAutomationNode* pan;
2117
2118         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2119                 if (pan->view) {
2120                         pan->view->line();
2121                 }
2122         }
2123
2124         return boost::shared_ptr<AutomationLine>();
2125 }
2126
2127 void
2128 RouteTimeAxisView::reset_processor_automation_curves ()
2129 {
2130         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2131                 (*i)->reset();
2132         }
2133 }
2134
2135 void
2136 RouteTimeAxisView::update_rec_display ()
2137 {
2138         RouteUI::update_rec_display ();
2139         name_entry.set_sensitive (!_route->record_enabled());
2140 }
2141
2142 void
2143 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2144 {
2145         if (apply_to_selection) {
2146                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2147         } else {
2148
2149                 if (_view) {
2150                         _view->set_layer_display (d);
2151                 }
2152
2153                 set_gui_property (X_("layer-display"), enum_2_string (d));
2154         }
2155 }
2156
2157 LayerDisplay
2158 RouteTimeAxisView::layer_display () const
2159 {
2160         if (_view) {
2161                 return _view->layer_display ();
2162         }
2163
2164         /* we don't know, since we don't have a _view, so just return something */
2165         return Overlaid;
2166 }
2167
2168
2169
2170 boost::shared_ptr<AutomationTimeAxisView>
2171 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2172 {
2173         AutomationTracks::iterator i = _automation_tracks.find(param);
2174         if (i != _automation_tracks.end()) {
2175                 return i->second;
2176         } else {
2177                 return boost::shared_ptr<AutomationTimeAxisView>();
2178         }
2179 }
2180
2181 void
2182 RouteTimeAxisView::fast_update ()
2183 {
2184         gm.get_level_meter().update_meters ();
2185 }
2186
2187 void
2188 RouteTimeAxisView::hide_meter ()
2189 {
2190         clear_meter ();
2191         gm.get_level_meter().hide_meters ();
2192 }
2193
2194 void
2195 RouteTimeAxisView::show_meter ()
2196 {
2197         reset_meter ();
2198 }
2199
2200 void
2201 RouteTimeAxisView::reset_meter ()
2202 {
2203         if (Config->get_show_track_meters()) {
2204                 gm.get_level_meter().setup_meters (height-5);
2205         } else {
2206                 hide_meter ();
2207         }
2208 }
2209
2210 void
2211 RouteTimeAxisView::clear_meter ()
2212 {
2213         gm.get_level_meter().clear_meters ();
2214 }
2215
2216 void
2217 RouteTimeAxisView::meter_changed ()
2218 {
2219         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2220         reset_meter();
2221 }
2222
2223 void
2224 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2225 {
2226         reset_meter ();
2227 }
2228
2229 void
2230 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2231 {
2232         using namespace Menu_Helpers;
2233
2234         if (!_underlay_streams.empty()) {
2235                 MenuList& parent_items = parent_menu->items();
2236                 Menu* gs_menu = manage (new Menu);
2237                 gs_menu->set_name ("ArdourContextMenu");
2238                 MenuList& gs_items = gs_menu->items();
2239
2240                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2241
2242                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2243                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2244                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2245                 }
2246         }
2247 }
2248
2249 bool
2250 RouteTimeAxisView::set_underlay_state()
2251 {
2252         if (!underlay_xml_node) {
2253                 return false;
2254         }
2255
2256         XMLNodeList nlist = underlay_xml_node->children();
2257         XMLNodeConstIterator niter;
2258         XMLNode *child_node;
2259
2260         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2261                 child_node = *niter;
2262
2263                 if (child_node->name() != "Underlay") {
2264                         continue;
2265                 }
2266
2267                 XMLProperty* prop = child_node->property ("id");
2268                 if (prop) {
2269                         PBD::ID id (prop->value());
2270
2271                         RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2272
2273                         if (v) {
2274                                 add_underlay(v->view(), false);
2275                         }
2276                 }
2277         }
2278
2279         return false;
2280 }
2281
2282 void
2283 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2284 {
2285         if (!v) {
2286                 return;
2287         }
2288
2289         RouteTimeAxisView& other = v->trackview();
2290
2291         if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2292                 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2293                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2294                         /*NOTREACHED*/
2295                 }
2296
2297                 _underlay_streams.push_back(v);
2298                 other._underlay_mirrors.push_back(this);
2299
2300                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2301
2302 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2303                 if (update_xml) {
2304                         if (!underlay_xml_node) {
2305                                 underlay_xml_node = xml_node->add_child("Underlays");
2306                         }
2307
2308                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2309                         XMLProperty* prop = node->add_property("id");
2310                         prop->set_value(v->trackview().route()->id().to_s());
2311                 }
2312 #endif
2313         }
2314 }
2315
2316 void
2317 RouteTimeAxisView::remove_underlay (StreamView* v)
2318 {
2319         if (!v) {
2320                 return;
2321         }
2322
2323         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2324         RouteTimeAxisView& other = v->trackview();
2325
2326         if (it != _underlay_streams.end()) {
2327                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2328
2329                 if (gm == other._underlay_mirrors.end()) {
2330                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2331                         /*NOTREACHED*/
2332                 }
2333
2334                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2335
2336                 _underlay_streams.erase(it);
2337                 other._underlay_mirrors.erase(gm);
2338
2339                 if (underlay_xml_node) {
2340                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2341                 }
2342         }
2343 }
2344
2345 void
2346 RouteTimeAxisView::set_button_names ()
2347 {
2348         if (_route && _route->solo_safe()) {
2349                 solo_button->remove ();
2350                 if (solo_safe_pixbuf == 0) {
2351                         solo_safe_pixbuf = ::get_icon("solo-safe-icon");
2352                 }
2353                 solo_button->set_image (solo_safe_pixbuf);
2354                 solo_button->set_text (string());
2355         } else {
2356                 solo_button->set_image (Glib::RefPtr<Gdk::Pixbuf>());
2357                 if (Config->get_solo_control_is_listen_control()) {
2358                         switch (Config->get_listen_position()) {
2359                         case AfterFaderListen:
2360                                 solo_button->set_text (_("A"));
2361                                 break;
2362                         case PreFaderListen:
2363                                 solo_button->set_text (_("P"));
2364                                 break;
2365                         }
2366                 } else {
2367                         solo_button->set_text (_("s"));
2368                 }
2369         }
2370         mute_button->set_text (_("m"));
2371 }
2372
2373 Gtk::CheckMenuItem*
2374 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2375 {
2376         ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2377         if (i != _main_automation_menu_map.end()) {
2378                 return i->second;
2379         }
2380
2381         i = _subplugin_menu_map.find (param);
2382         if (i != _subplugin_menu_map.end()) {
2383                 return i->second;
2384         }
2385
2386         return 0;
2387 }
2388
2389 void
2390 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2391 {
2392         boost::shared_ptr<AutomationControl> c = _route->gain_control();
2393         if (!c) {
2394                 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2395                 return;
2396         }
2397
2398         gain_track.reset (new AutomationTimeAxisView (_session,
2399                                                       _route, _route->amp(), c, param,
2400                                                       _editor,
2401                                                       *this,
2402                                                       false,
2403                                                       parent_canvas,
2404                                                       _route->amp()->describe_parameter(param)));
2405
2406         if (_view) {
2407                 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2408         }
2409
2410         add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2411 }
2412
2413 static
2414 void add_region_to_list (RegionView* rv, Playlist::RegionList* l)
2415 {
2416         l->push_back (rv->region());
2417 }
2418
2419 RegionView*
2420 RouteTimeAxisView::combine_regions ()
2421 {
2422         /* as of may 2011, we do not offer uncombine for MIDI tracks
2423          */
2424
2425         if (!is_audio_track()) {
2426                 return 0;
2427         }
2428
2429         if (!_view) {
2430                 return 0;
2431         }
2432
2433         Playlist::RegionList selected_regions;
2434         boost::shared_ptr<Playlist> playlist = track()->playlist();
2435
2436         _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2437
2438         if (selected_regions.size() < 2) {
2439                 return 0;
2440         }
2441
2442         playlist->clear_changes ();
2443         boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2444
2445         _session->add_command (new StatefulDiffCommand (playlist));
2446         /* make the new region be selected */
2447
2448         return _view->find_view (compound_region);
2449 }
2450
2451 void
2452 RouteTimeAxisView::uncombine_regions ()
2453 {
2454         /* as of may 2011, we do not offer uncombine for MIDI tracks
2455          */
2456         if (!is_audio_track()) {
2457                 return;
2458         }
2459
2460         if (!_view) {
2461                 return;
2462         }
2463
2464         Playlist::RegionList selected_regions;
2465         boost::shared_ptr<Playlist> playlist = track()->playlist();
2466
2467         /* have to grab selected regions first because the uncombine is going
2468          * to change that in the middle of the list traverse
2469          */
2470
2471         _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2472
2473         playlist->clear_changes ();
2474
2475         for (Playlist::RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2476                 playlist->uncombine (*i);
2477         }
2478
2479         _session->add_command (new StatefulDiffCommand (playlist));
2480 }
2481
2482 string
2483 RouteTimeAxisView::state_id() const
2484 {
2485         return string_compose ("rtav %1", _route->id().to_s());
2486 }
2487
2488
2489 void
2490 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2491 {
2492         TimeAxisView::remove_child (c);
2493         
2494         boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2495         if (a) {
2496                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2497                         if (i->second == a) {
2498                                 _automation_tracks.erase (i);
2499                                 return;
2500                         }
2501                 }
2502         }
2503 }