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