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