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