9cb26d162235db8e139d2f3a841d0de2715745fd
[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(), -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(), -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(), -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         _session->add_command (new StatefulDiffCommand (pl));
1445
1446         return true;
1447 }
1448
1449
1450 struct PlaylistSorter {
1451     bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1452             return a->sort_id() < b->sort_id();
1453     }
1454 };
1455
1456 void
1457 RouteTimeAxisView::build_playlist_menu ()
1458 {
1459         using namespace Menu_Helpers;
1460
1461         if (!is_track()) {
1462                 return;
1463         }
1464
1465         delete playlist_action_menu;
1466         playlist_action_menu = new Menu;
1467         playlist_action_menu->set_name ("ArdourContextMenu");
1468
1469         MenuList& playlist_items = playlist_action_menu->items();
1470         playlist_action_menu->set_name ("ArdourContextMenu");
1471         playlist_items.clear();
1472
1473         RadioMenuItem::Group playlist_group;
1474         boost::shared_ptr<Track> tr = track ();
1475
1476         vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
1477
1478         /* sort the playlists */
1479         PlaylistSorter cmp;
1480         sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1481
1482         /* add the playlists to the menu */
1483         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1484                 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1485                 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1486                 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1487
1488                 if (tr->playlist()->id() == (*i)->id()) {
1489                         item->set_active();
1490
1491                 }
1492         }
1493
1494         playlist_items.push_back (SeparatorElem());
1495         playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1496         playlist_items.push_back (SeparatorElem());
1497
1498         if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::select.property_id)) {
1499                 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1500                 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1501
1502         } else {
1503                 // Use a label which tells the user what is happening
1504                 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1505                 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1506
1507         }
1508
1509         playlist_items.push_back (SeparatorElem());
1510         playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1511         playlist_items.push_back (SeparatorElem());
1512
1513         playlist_items.push_back (MenuElem(_("Select From All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1514 }
1515
1516 void
1517 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1518 {
1519         assert (is_track());
1520
1521         // exit if we were triggered by deactivating the old playlist
1522         if (!item->get_active()) {
1523                 return;
1524         }
1525
1526         boost::shared_ptr<Playlist> pl (wpl.lock());
1527
1528         if (!pl) {
1529                 return;
1530         }
1531
1532         if (track()->playlist() == pl) {
1533                 // exit when use_playlist is called by the creation of the playlist menu
1534                 // or the playlist choice is unchanged
1535                 return;
1536         }
1537
1538         track()->use_playlist (pl);
1539         
1540         RouteGroup* rg = route_group();
1541         
1542         if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) {
1543                 std::string group_string = "." + rg->name() + ".";
1544                 
1545                 std::string take_name = pl->name();
1546                 std::string::size_type idx = take_name.find(group_string);
1547                 
1548                 if (idx == std::string::npos)
1549                         return;
1550                 
1551                 take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1552                 
1553                 boost::shared_ptr<RouteList> rl (rg->route_list());
1554                 
1555                 for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1556                         if ((*i) == this->route()) {
1557                                 continue;
1558                         }
1559
1560                         std::string playlist_name = (*i)->name()+group_string+take_name;
1561                         
1562                         boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1563                         if (!track) {
1564                                 continue;
1565                         }
1566
1567                         if (track->freeze_state() == Track::Frozen) {
1568                                 /* Don't change playlists of frozen tracks */
1569                                 continue;
1570                         }
1571                         
1572                         boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1573                         if (!ipl) {
1574                                 // No playlist for this track for this take yet, make it
1575                                 track->use_new_playlist();
1576                                 track->playlist()->set_name(playlist_name);
1577                         } else {
1578                                 track->use_playlist(ipl);
1579                         }
1580                 }
1581         }
1582 }
1583
1584 void
1585 RouteTimeAxisView::update_playlist_tip ()
1586 {
1587         RouteGroup* rg = route_group ();
1588         if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::select.property_id)) {
1589                 string group_string = "." + rg->name() + ".";
1590                 
1591                 string take_name = track()->playlist()->name();
1592                 string::size_type idx = take_name.find(group_string);
1593                 
1594                 if (idx != string::npos) {
1595                         /* find the bit containing the take number / name */
1596                         take_name = take_name.substr (idx + group_string.length());
1597
1598                         /* set the playlist button tooltip to the take name */
1599                         ARDOUR_UI::instance()->set_tip (
1600                                 playlist_button,
1601                                 string_compose(_("Take: %1.%2"),
1602                                         Glib::Markup::escape_text(rg->name()),
1603                                         Glib::Markup::escape_text(take_name))
1604                                 );
1605                         
1606                         return;
1607                 }
1608         }
1609
1610         /* set the playlist button tooltip to the playlist name */
1611         ARDOUR_UI::instance()->set_tip (playlist_button, _("Playlist") + std::string(": ") + Glib::Markup::escape_text(track()->playlist()->name()));
1612 }
1613
1614
1615 void
1616 RouteTimeAxisView::show_playlist_selector ()
1617 {
1618         _editor.playlist_selector().show_for (this);
1619 }
1620
1621 void
1622 RouteTimeAxisView::map_frozen ()
1623 {
1624         if (!is_track()) {
1625                 return;
1626         }
1627
1628         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1629
1630         switch (track()->freeze_state()) {
1631         case Track::Frozen:
1632                 playlist_button.set_sensitive (false);
1633                 rec_enable_button->set_sensitive (false);
1634                 break;
1635         default:
1636                 playlist_button.set_sensitive (true);
1637                 rec_enable_button->set_sensitive (true);
1638                 break;
1639         }
1640 }
1641
1642 void
1643 RouteTimeAxisView::color_handler ()
1644 {
1645         //case cTimeStretchOutline:
1646         if (timestretch_rect) {
1647                 timestretch_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_TimeStretchOutline());
1648         }
1649         //case cTimeStretchFill:
1650         if (timestretch_rect) {
1651                 timestretch_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_TimeStretchFill());
1652         }
1653
1654         reset_meter();
1655 }
1656
1657 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1658  *  Will add track if necessary.
1659  */
1660 void
1661 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1662 {
1663         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1664         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1665
1666         if (!track) {
1667                 /* it doesn't exist yet, so we don't care about the button state: just add it */
1668                 create_automation_child (param, true);
1669         } else {
1670                 assert (menu);
1671                 bool yn = menu->get_active();
1672                 bool changed = false;
1673
1674                 if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
1675
1676                         /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1677                            will have done that for us.
1678                         */
1679
1680                         if (changed && !no_redraw) {
1681                                 request_redraw ();
1682                         }
1683                 }
1684         }
1685 }
1686
1687 void
1688 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1689 {
1690         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1691
1692         if (!track) {
1693                 return;
1694         }
1695
1696         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1697
1698         if (menu && !_hidden) {
1699                 ignore_toggle = true;
1700                 menu->set_active (false);
1701                 ignore_toggle = false;
1702         }
1703
1704         if (_route && !no_redraw) {
1705                 request_redraw ();
1706         }
1707 }
1708
1709
1710 void
1711 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
1712 {
1713         if (apply_to_selection) {
1714                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
1715         } else {
1716                 no_redraw = true;
1717
1718                 /* Show our automation */
1719
1720                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1721                         i->second->set_marked_for_display (true);
1722
1723                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1724
1725                         if (menu) {
1726                                 menu->set_active(true);
1727                         }
1728                 }
1729
1730
1731                 /* Show processor automation */
1732
1733                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1734                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1735                                 if ((*ii)->view == 0) {
1736                                         add_processor_automation_curve ((*i)->processor, (*ii)->what);
1737                                 }
1738
1739                                 (*ii)->menu_item->set_active (true);
1740                         }
1741                 }
1742
1743                 no_redraw = false;
1744
1745                 /* Redraw */
1746
1747                 request_redraw ();
1748         }
1749 }
1750
1751 void
1752 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
1753 {
1754         if (apply_to_selection) {
1755                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
1756         } else {
1757                 no_redraw = true;
1758
1759                 /* Show our automation */
1760
1761                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1762                         if (i->second->has_automation()) {
1763                                 i->second->set_marked_for_display (true);
1764
1765                                 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1766                                 if (menu) {
1767                                         menu->set_active(true);
1768                                 }
1769                         }
1770                 }
1771
1772                 /* Show processor automation */
1773
1774                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1775                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1776                                 if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
1777                                         (*ii)->menu_item->set_active (true);
1778                                 }
1779                         }
1780                 }
1781
1782                 no_redraw = false;
1783
1784                 request_redraw ();
1785         }
1786 }
1787
1788 void
1789 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
1790 {
1791         if (apply_to_selection) {
1792                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
1793         } else {
1794                 no_redraw = true;
1795
1796                 /* Hide our automation */
1797
1798                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1799                         i->second->set_marked_for_display (false);
1800
1801                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1802
1803                         if (menu) {
1804                                 menu->set_active (false);
1805                         }
1806                 }
1807
1808                 /* Hide processor automation */
1809
1810                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1811                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1812                                 (*ii)->menu_item->set_active (false);
1813                         }
1814                 }
1815
1816                 no_redraw = false;
1817                 request_redraw ();
1818         }
1819 }
1820
1821
1822 void
1823 RouteTimeAxisView::region_view_added (RegionView* rv)
1824 {
1825         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
1826         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1827                 boost::shared_ptr<AutomationTimeAxisView> atv;
1828
1829                 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1830                         atv->add_ghost(rv);
1831                 }
1832         }
1833
1834         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
1835                 (*i)->add_ghost(rv);
1836         }
1837 }
1838
1839 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1840 {
1841         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1842                 delete *i;
1843         }
1844 }
1845
1846
1847 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1848 {
1849         parent.remove_processor_automation_node (this);
1850 }
1851
1852 void
1853 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1854 {
1855         if (pan->view) {
1856                 remove_child (pan->view);
1857         }
1858 }
1859
1860 RouteTimeAxisView::ProcessorAutomationNode*
1861 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1862 {
1863         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1864
1865                 if ((*i)->processor == processor) {
1866
1867                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1868                                 if ((*ii)->what == what) {
1869                                         return *ii;
1870                                 }
1871                         }
1872                 }
1873         }
1874
1875         return 0;
1876 }
1877
1878 /** Add an AutomationTimeAxisView to display automation for a processor's parameter */
1879 void
1880 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1881 {
1882         string name;
1883         ProcessorAutomationNode* pan;
1884
1885         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1886                 /* session state may never have been saved with new plugin */
1887                 error << _("programming error: ")
1888                       << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
1889                                          processor->name(), what.type(), (int) what.channel(), what.id() )
1890                       << endmsg;
1891                 /*NOTREACHED*/
1892                 return;
1893         }
1894
1895         if (pan->view) {
1896                 return;
1897         }
1898
1899         boost::shared_ptr<AutomationControl> control
1900                 = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
1901         
1902         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
1903                 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
1904                                             _editor, *this, false, parent_canvas, 
1905                                             processor->describe_parameter (what), processor->name()));
1906
1907         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
1908
1909         add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
1910
1911         if (_view) {
1912                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
1913         }
1914 }
1915
1916 void
1917 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
1918 {
1919         if (!_hidden) {
1920                 pan->menu_item->set_active (false);
1921         }
1922
1923         if (!no_redraw) {
1924                 request_redraw ();
1925         }
1926 }
1927
1928 void
1929 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
1930 {
1931         boost::shared_ptr<Processor> processor (p.lock ());
1932
1933         if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
1934                 /* The Amp processor is a special case and is dealt with separately */
1935                 return;
1936         }
1937
1938         set<Evoral::Parameter> existing;
1939
1940         processor->what_has_data (existing);
1941
1942         for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
1943                 
1944                 Evoral::Parameter param (*i);
1945                 boost::shared_ptr<AutomationLine> al;
1946
1947                 if ((al = find_processor_automation_curve (processor, param)) != 0) {
1948                         al->queue_reset ();
1949                 } else {
1950                         add_processor_automation_curve (processor, param);
1951                 }
1952         }
1953 }
1954
1955 void
1956 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
1957 {
1958         using namespace Menu_Helpers;
1959
1960         add_child (track);
1961
1962         track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
1963
1964         _automation_tracks[param] = track;
1965
1966         /* existing state overrides "show" argument */
1967         string s = track->gui_property ("visible");
1968         if (!s.empty()) { 
1969                 show = string_is_affirmative (s);
1970         }
1971
1972         /* this might or might not change the visibility status, so don't rely on it */
1973         track->set_marked_for_display (show);
1974
1975         if (show && !no_redraw) {
1976                 request_redraw ();
1977         }
1978
1979         if (!EventTypeMap::instance().is_midi_parameter(param)) {
1980                 /* MIDI-related parameters are always in the menu, there's no
1981                    reason to rebuild the menu just because we added a automation
1982                    lane for one of them. But if we add a non-MIDI automation
1983                    lane, then we need to invalidate the display menu.
1984                 */
1985                 delete display_menu;
1986                 display_menu = 0;
1987         }
1988 }
1989
1990 void
1991 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
1992 {
1993         boost::shared_ptr<Processor> processor (p.lock ());
1994
1995         if (!processor || !processor->display_to_user ()) {
1996                 return;
1997         }
1998
1999         /* we use this override to veto the Amp processor from the plugin menu,
2000            as its automation lane can be accessed using the special "Fader" menu
2001            option
2002         */
2003
2004         if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
2005                 return;
2006         }
2007
2008         using namespace Menu_Helpers;
2009         ProcessorAutomationInfo *rai;
2010         list<ProcessorAutomationInfo*>::iterator x;
2011
2012         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2013
2014         if (automatable.empty()) {
2015                 return;
2016         }
2017
2018         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2019                 if ((*x)->processor == processor) {
2020                         break;
2021                 }
2022         }
2023
2024         if (x == processor_automation.end()) {
2025
2026                 rai = new ProcessorAutomationInfo (processor);
2027                 processor_automation.push_back (rai);
2028
2029         } else {
2030
2031                 rai = *x;
2032
2033         }
2034
2035         /* any older menu was deleted at the top of processors_changed()
2036            when we cleared the subplugin menu.
2037         */
2038
2039         rai->menu = manage (new Menu);
2040         MenuList& items = rai->menu->items();
2041         rai->menu->set_name ("ArdourContextMenu");
2042
2043         items.clear ();
2044
2045         std::set<Evoral::Parameter> has_visible_automation;
2046         AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
2047
2048         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2049
2050                 ProcessorAutomationNode* pan;
2051                 Gtk::CheckMenuItem* mitem;
2052
2053                 string name = processor->describe_parameter (*i);
2054
2055                 items.push_back (CheckMenuElem (name));
2056                 mitem = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
2057                 
2058                 _subplugin_menu_map[*i] = mitem;
2059
2060                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2061                         mitem->set_active(true);
2062                 }
2063
2064                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2065
2066                         /* new item */
2067
2068                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2069
2070                         rai->lines.push_back (pan);
2071
2072                 } else {
2073
2074                         pan->menu_item = mitem;
2075
2076                 }
2077
2078                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2079         }
2080
2081         /* add the menu for this processor, because the subplugin
2082            menu is always cleared at the top of processors_changed().
2083            this is the result of some poor design in gtkmm and/or
2084            GTK+.
2085         */
2086
2087         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2088         rai->valid = true;
2089 }
2090
2091 void
2092 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2093                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2094 {
2095         bool showit = pan->menu_item->get_active();
2096         bool redraw = false;
2097
2098         if (pan->view == 0 && showit) {
2099                 add_processor_automation_curve (rai->processor, pan->what);
2100                 redraw = true;
2101         }
2102
2103         if (pan->view && pan->view->set_marked_for_display (showit)) {
2104                 redraw = true;
2105         }
2106         
2107         if (redraw && !no_redraw) {
2108                 request_redraw ();
2109         }
2110 }
2111
2112 void
2113 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2114 {
2115         if (c.type == RouteProcessorChange::MeterPointChange) {
2116                 /* nothing to do if only the meter point has changed */
2117                 return;
2118         }
2119
2120         using namespace Menu_Helpers;
2121
2122         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2123                 (*i)->valid = false;
2124         }
2125
2126         setup_processor_menu_and_curves ();
2127
2128         bool deleted_processor_automation = false;
2129
2130         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2131
2132                 list<ProcessorAutomationInfo*>::iterator tmp;
2133
2134                 tmp = i;
2135                 ++tmp;
2136
2137                 if (!(*i)->valid) {
2138
2139                         delete *i;
2140                         processor_automation.erase (i);
2141                         deleted_processor_automation = true;
2142
2143                 }
2144
2145                 i = tmp;
2146         }
2147
2148         if (deleted_processor_automation && !no_redraw) {
2149                 request_redraw ();
2150         }
2151 }
2152
2153 boost::shared_ptr<AutomationLine>
2154 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2155 {
2156         ProcessorAutomationNode* pan;
2157
2158         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2159                 if (pan->view) {
2160                         pan->view->line();
2161                 }
2162         }
2163
2164         return boost::shared_ptr<AutomationLine>();
2165 }
2166
2167 void
2168 RouteTimeAxisView::reset_processor_automation_curves ()
2169 {
2170         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2171                 (*i)->reset();
2172         }
2173 }
2174
2175 bool
2176 RouteTimeAxisView::can_edit_name () const
2177 {
2178         /* we do not allow track name changes if it is record enabled
2179          */
2180         return !_route->record_enabled();
2181 }
2182
2183 void
2184 RouteTimeAxisView::update_rec_display ()
2185 {
2186         RouteUI::update_rec_display ();
2187 }
2188
2189 void
2190 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2191 {
2192         if (_ignore_set_layer_display) {
2193                 return;
2194         }
2195         
2196         if (apply_to_selection) {
2197                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2198         } else {
2199
2200                 if (_view) {
2201                         _view->set_layer_display (d);
2202                 }
2203
2204                 set_gui_property (X_("layer-display"), enum_2_string (d));
2205         }
2206 }
2207
2208 LayerDisplay
2209 RouteTimeAxisView::layer_display () const
2210 {
2211         if (_view) {
2212                 return _view->layer_display ();
2213         }
2214
2215         /* we don't know, since we don't have a _view, so just return something */
2216         return Overlaid;
2217 }
2218
2219
2220
2221 boost::shared_ptr<AutomationTimeAxisView>
2222 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2223 {
2224         AutomationTracks::iterator i = _automation_tracks.find(param);
2225         if (i != _automation_tracks.end()) {
2226                 return i->second;
2227         } else {
2228                 return boost::shared_ptr<AutomationTimeAxisView>();
2229         }
2230 }
2231
2232 void
2233 RouteTimeAxisView::fast_update ()
2234 {
2235         gm.get_level_meter().update_meters ();
2236 }
2237
2238 void
2239 RouteTimeAxisView::hide_meter ()
2240 {
2241         clear_meter ();
2242         gm.get_level_meter().hide_meters ();
2243 }
2244
2245 void
2246 RouteTimeAxisView::show_meter ()
2247 {
2248         reset_meter ();
2249 }
2250
2251 void
2252 RouteTimeAxisView::reset_meter ()
2253 {
2254         if (Config->get_show_track_meters()) {
2255                 int meter_width = 3;
2256                 if (_route && _route->shared_peak_meter()->input_streams().n_total() == 1) {
2257                         meter_width = 6;
2258                 }
2259                 gm.get_level_meter().setup_meters (height - 9, meter_width);
2260         } else {
2261                 hide_meter ();
2262         }
2263 }
2264
2265 void
2266 RouteTimeAxisView::clear_meter ()
2267 {
2268         gm.get_level_meter().clear_meters ();
2269 }
2270
2271 void
2272 RouteTimeAxisView::meter_changed ()
2273 {
2274         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2275         reset_meter();
2276         if (_route && !no_redraw) {
2277                 request_redraw ();
2278         }
2279         // reset peak when meter point changes
2280         gm.reset_peak_display();
2281 }
2282
2283 void
2284 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2285 {
2286         reset_meter ();
2287         if (_route && !no_redraw) {
2288                 request_redraw ();
2289         }
2290 }
2291
2292 void
2293 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2294 {
2295         using namespace Menu_Helpers;
2296
2297         if (!_underlay_streams.empty()) {
2298                 MenuList& parent_items = parent_menu->items();
2299                 Menu* gs_menu = manage (new Menu);
2300                 gs_menu->set_name ("ArdourContextMenu");
2301                 MenuList& gs_items = gs_menu->items();
2302
2303                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2304
2305                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2306                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2307                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2308                 }
2309         }
2310 }
2311
2312 bool
2313 RouteTimeAxisView::set_underlay_state()
2314 {
2315         if (!underlay_xml_node) {
2316                 return false;
2317         }
2318
2319         XMLNodeList nlist = underlay_xml_node->children();
2320         XMLNodeConstIterator niter;
2321         XMLNode *child_node;
2322
2323         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2324                 child_node = *niter;
2325
2326                 if (child_node->name() != "Underlay") {
2327                         continue;
2328                 }
2329
2330                 XMLProperty* prop = child_node->property ("id");
2331                 if (prop) {
2332                         PBD::ID id (prop->value());
2333
2334                         RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2335
2336                         if (v) {
2337                                 add_underlay(v->view(), false);
2338                         }
2339                 }
2340         }
2341
2342         return false;
2343 }
2344
2345 void
2346 RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
2347 {
2348         if (!v) {
2349                 return;
2350         }
2351
2352         RouteTimeAxisView& other = v->trackview();
2353
2354         if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2355                 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2356                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2357                         /*NOTREACHED*/
2358                 }
2359
2360                 _underlay_streams.push_back(v);
2361                 other._underlay_mirrors.push_back(this);
2362
2363                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2364
2365 #ifdef GUI_OBJECT_STATE_FIX_REQUIRED
2366                 if (update_xml) {
2367                         if (!underlay_xml_node) {
2368                                 underlay_xml_node = xml_node->add_child("Underlays");
2369                         }
2370
2371                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2372                         XMLProperty* prop = node->add_property("id");
2373                         prop->set_value(v->trackview().route()->id().to_s());
2374                 }
2375 #endif
2376         }
2377 }
2378
2379 void
2380 RouteTimeAxisView::remove_underlay (StreamView* v)
2381 {
2382         if (!v) {
2383                 return;
2384         }
2385
2386         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2387         RouteTimeAxisView& other = v->trackview();
2388
2389         if (it != _underlay_streams.end()) {
2390                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2391
2392                 if (gm == other._underlay_mirrors.end()) {
2393                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2394                         /*NOTREACHED*/
2395                 }
2396
2397                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2398
2399                 _underlay_streams.erase(it);
2400                 other._underlay_mirrors.erase(gm);
2401
2402                 if (underlay_xml_node) {
2403                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2404                 }
2405         }
2406 }
2407
2408 void
2409 RouteTimeAxisView::set_button_names ()
2410 {
2411         if (_route && _route->solo_safe()) {
2412                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2413         } else {
2414                 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2415         }
2416         if (Config->get_solo_control_is_listen_control()) {
2417                 switch (Config->get_listen_position()) {
2418                         case AfterFaderListen:
2419                                 solo_button->set_text (_("A"));
2420                                 ARDOUR_UI::instance()->set_tip (*solo_button, _("After-fade listen (AFL)"));
2421                                 break;
2422                         case PreFaderListen:
2423                                 solo_button->set_text (_("P"));
2424                                 ARDOUR_UI::instance()->set_tip (*solo_button, _("Pre-fade listen (PFL)"));
2425                         break;
2426                 }
2427         } else {
2428                 solo_button->set_text (_("s"));
2429                 ARDOUR_UI::instance()->set_tip (*solo_button, _("Solo"));
2430         }
2431         mute_button->set_text (_("m"));
2432 }
2433
2434 Gtk::CheckMenuItem*
2435 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2436 {
2437         ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2438         if (i != _main_automation_menu_map.end()) {
2439                 return i->second;
2440         }
2441
2442         i = _subplugin_menu_map.find (param);
2443         if (i != _subplugin_menu_map.end()) {
2444                 return i->second;
2445         }
2446
2447         return 0;
2448 }
2449
2450 void
2451 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2452 {
2453         boost::shared_ptr<AutomationControl> c = _route->gain_control();
2454         if (!c) {
2455                 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2456                 return;
2457         }
2458
2459         gain_track.reset (new AutomationTimeAxisView (_session,
2460                                                       _route, _route->amp(), c, param,
2461                                                       _editor,
2462                                                       *this,
2463                                                       false,
2464                                                       parent_canvas,
2465                                                       _route->amp()->describe_parameter(param)));
2466
2467         if (_view) {
2468                 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2469         }
2470
2471         add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2472 }
2473
2474 static
2475 void add_region_to_list (RegionView* rv, RegionList* l)
2476 {
2477         l->push_back (rv->region());
2478 }
2479
2480 RegionView*
2481 RouteTimeAxisView::combine_regions ()
2482 {
2483         /* as of may 2011, we do not offer uncombine for MIDI tracks
2484          */
2485
2486         if (!is_audio_track()) {
2487                 return 0;
2488         }
2489
2490         if (!_view) {
2491                 return 0;
2492         }
2493
2494         RegionList selected_regions;
2495         boost::shared_ptr<Playlist> playlist = track()->playlist();
2496
2497         _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2498
2499         if (selected_regions.size() < 2) {
2500                 return 0;
2501         }
2502
2503         playlist->clear_changes ();
2504         boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
2505
2506         _session->add_command (new StatefulDiffCommand (playlist));
2507         /* make the new region be selected */
2508
2509         return _view->find_view (compound_region);
2510 }
2511
2512 void
2513 RouteTimeAxisView::uncombine_regions ()
2514 {
2515         /* as of may 2011, we do not offer uncombine for MIDI tracks
2516          */
2517         if (!is_audio_track()) {
2518                 return;
2519         }
2520
2521         if (!_view) {
2522                 return;
2523         }
2524
2525         RegionList selected_regions;
2526         boost::shared_ptr<Playlist> playlist = track()->playlist();
2527
2528         /* have to grab selected regions first because the uncombine is going
2529          * to change that in the middle of the list traverse
2530          */
2531
2532         _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
2533
2534         playlist->clear_changes ();
2535
2536         for (RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
2537                 playlist->uncombine (*i);
2538         }
2539
2540         _session->add_command (new StatefulDiffCommand (playlist));
2541 }
2542
2543 string
2544 RouteTimeAxisView::state_id() const
2545 {
2546         return string_compose ("rtav %1", _route->id().to_s());
2547 }
2548
2549
2550 void
2551 RouteTimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> c)
2552 {
2553         TimeAxisView::remove_child (c);
2554         
2555         boost::shared_ptr<AutomationTimeAxisView> a = boost::dynamic_pointer_cast<AutomationTimeAxisView> (c);
2556         if (a) {
2557                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
2558                         if (i->second == a) {
2559                                 _automation_tracks.erase (i);
2560                                 return;
2561                         }
2562                 }
2563         }
2564 }