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