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