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