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