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