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