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