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