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