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