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