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