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