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