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