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