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