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