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