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