Don't hide solo/mute/rec enable for the smallest track height, as there appears to...
[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                 
866                 controls_table.set_border_width (2);
867                 
868                 reset_meter();
869                 show_name_entry ();
870                 hide_name_label ();
871
872                 gm.get_gain_slider().show();
873                 mute_button->show();
874                 if (!_route || _route->is_monitor()) {
875                         solo_button->hide();
876                 } else {
877                         solo_button->show();
878                 }
879                 if (rec_enable_button)
880                         rec_enable_button->show();
881
882                 route_group_button.show();
883                 automation_button.show();
884
885                 if (is_track() && track()->mode() == ARDOUR::Normal) {
886                         playlist_button.show();
887                 }
888
889         } else if (height >= preset_height (HeightSmaller)) {
890
891                 controls_table.set_border_width (2);
892                 
893                 reset_meter();
894                 show_name_entry ();
895                 hide_name_label ();
896
897                 gm.get_gain_slider().hide();
898                 mute_button->show();
899                 if (!_route || _route->is_monitor()) {
900                         solo_button->hide();
901                 } else {
902                         solo_button->show();
903                 }
904                 if (rec_enable_button)
905                         rec_enable_button->show();
906
907                 route_group_button.hide ();
908                 automation_button.hide ();
909
910                 if (is_track() && track()->mode() == ARDOUR::Normal) {
911                         playlist_button.hide ();
912                 }
913
914         } else {
915
916                 controls_table.set_border_width (0);
917         
918         }
919
920         if (height_changed && !no_redraw) {
921                 /* only emit the signal if the height really changed */
922                  _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
923         }
924 }
925
926 void
927 RouteTimeAxisView::set_color (Gdk::Color const & c)
928 {
929         RouteUI::set_color (c);
930         
931         if (_view) {
932                 _view->apply_color (_color, StreamView::RegionColor);
933         }
934 }
935
936 void
937 RouteTimeAxisView::reset_samples_per_unit ()
938 {
939         set_samples_per_unit (_editor.get_current_zoom());
940 }
941
942 void
943 RouteTimeAxisView::horizontal_position_changed ()
944 {
945         if (_view) {
946                 _view->horizontal_position_changed ();
947         }
948 }
949
950 void
951 RouteTimeAxisView::set_samples_per_unit (double spu)
952 {
953         double speed = 1.0;
954
955         if (track()) {
956                 speed = track()->speed();
957         }
958
959         if (_view) {
960                 _view->set_samples_per_unit (spu * speed);
961         }
962
963         TimeAxisView::set_samples_per_unit (spu * speed);
964 }
965
966 void
967 RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
968 {
969         if (!mitem->get_active()) {
970                 /* this is one of the two calls made when these radio menu items change status. this one
971                    is for the item that became inactive, and we want to ignore it.
972                 */
973                 return;
974         }
975
976         if (apply_to_selection) {
977                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
978         } else {
979                 if (track ()) {
980                         track()->set_align_choice (choice);
981                 }
982         }
983 }
984
985 void
986 RouteTimeAxisView::rename_current_playlist ()
987 {
988         ArdourPrompter prompter (true);
989         string name;
990
991         boost::shared_ptr<Track> tr = track();
992         if (!tr || tr->destructive()) {
993                 return;
994         }
995
996         boost::shared_ptr<Playlist> pl = tr->playlist();
997         if (!pl) {
998                 return;
999         }
1000
1001         prompter.set_title (_("Rename Playlist"));
1002         prompter.set_prompt (_("New name for playlist:"));
1003         prompter.set_initial_text (pl->name());
1004         prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1005         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1006
1007         switch (prompter.run ()) {
1008         case Gtk::RESPONSE_ACCEPT:
1009                 prompter.get_result (name);
1010                 if (name.length()) {
1011                         pl->set_name (name);
1012                 }
1013                 break;
1014
1015         default:
1016                 break;
1017         }
1018 }
1019
1020 std::string
1021 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
1022 {
1023         std::string ret (basename);
1024
1025         std::string const group_string = "." + route_group()->name() + ".";
1026
1027         // iterate through all playlists
1028         int maxnumber = 0;
1029         for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1030                 std::string tmp = (*i)->name();
1031
1032                 std::string::size_type idx = tmp.find(group_string);
1033                 // find those which belong to this group
1034                 if (idx != string::npos) {
1035                         tmp = tmp.substr(idx + group_string.length());
1036
1037                         // and find the largest current number
1038                         int x = atoi(tmp.c_str());
1039                         if (x > maxnumber) {
1040                                 maxnumber = x;
1041                         }
1042                 }
1043         }
1044
1045         maxnumber++;
1046
1047         char buf[32];
1048         snprintf (buf, sizeof(buf), "%d", maxnumber);
1049
1050         ret = this->name() + "." + route_group()->name () + "." + buf;
1051
1052         return ret;
1053 }
1054
1055 void
1056 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1057 {
1058         string name;
1059
1060         boost::shared_ptr<Track> tr = track ();
1061         if (!tr || tr->destructive()) {
1062                 return;
1063         }
1064
1065         boost::shared_ptr<const Playlist> pl = tr->playlist();
1066         if (!pl) {
1067                 return;
1068         }
1069
1070         name = pl->name();
1071
1072         if (route_group() && route_group()->is_active()) {
1073                 name = resolve_new_group_playlist_name(name, playlists_before_op);
1074         }
1075
1076         while (_session->playlists->by_name(name)) {
1077                 name = Playlist::bump_name (name, *_session);
1078         }
1079
1080         // TODO: The prompter "new" button should be de-activated if the user
1081         // specifies a playlist name which already exists in the session.
1082
1083         if (prompt) {
1084
1085                 ArdourPrompter prompter (true);
1086
1087                 prompter.set_title (_("New Copy Playlist"));
1088                 prompter.set_prompt (_("Name for new playlist:"));
1089                 prompter.set_initial_text (name);
1090                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1091                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1092                 prompter.show_all ();
1093
1094                 switch (prompter.run ()) {
1095                 case Gtk::RESPONSE_ACCEPT:
1096                         prompter.get_result (name);
1097                         break;
1098
1099                 default:
1100                         return;
1101                 }
1102         }
1103
1104         if (name.length()) {
1105                 tr->use_copy_playlist ();
1106                 tr->playlist()->set_name (name);
1107         }
1108 }
1109
1110 void
1111 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1112 {
1113         string name;
1114
1115         boost::shared_ptr<Track> tr = track ();
1116         if (!tr || tr->destructive()) {
1117                 return;
1118         }
1119
1120         boost::shared_ptr<const Playlist> pl = tr->playlist();
1121         if (!pl) {
1122                 return;
1123         }
1124
1125         name = pl->name();
1126
1127         if (route_group() && route_group()->is_active()) {
1128                 name = resolve_new_group_playlist_name(name,playlists_before_op);
1129         }
1130
1131         while (_session->playlists->by_name(name)) {
1132                 name = Playlist::bump_name (name, *_session);
1133         }
1134
1135
1136         if (prompt) {
1137
1138                 ArdourPrompter prompter (true);
1139
1140                 prompter.set_title (_("New Playlist"));
1141                 prompter.set_prompt (_("Name for new playlist:"));
1142                 prompter.set_initial_text (name);
1143                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1144                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1145
1146                 switch (prompter.run ()) {
1147                 case Gtk::RESPONSE_ACCEPT:
1148                         prompter.get_result (name);
1149                         break;
1150
1151                 default:
1152                         return;
1153                 }
1154         }
1155
1156         if (name.length()) {
1157                 tr->use_new_playlist ();
1158                 tr->playlist()->set_name (name);
1159         }
1160 }
1161
1162 void
1163 RouteTimeAxisView::clear_playlist ()
1164 {
1165         boost::shared_ptr<Track> tr = track ();
1166         if (!tr || tr->destructive()) {
1167                 return;
1168         }
1169
1170         boost::shared_ptr<Playlist> pl = tr->playlist();
1171         if (!pl) {
1172                 return;
1173         }
1174
1175         _editor.clear_playlist (pl);
1176 }
1177
1178 void
1179 RouteTimeAxisView::speed_changed ()
1180 {
1181         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteTimeAxisView::reset_samples_per_unit, this));
1182 }
1183
1184 void
1185 RouteTimeAxisView::update_diskstream_display ()
1186 {
1187         if (!track()) {
1188                 return;
1189         }
1190
1191         map_frozen ();
1192 }
1193
1194 void
1195 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1196 {
1197         if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1198
1199                 /* special case: select/deselect all tracks */
1200                 if (_editor.get_selection().selected (this)) {
1201                         _editor.get_selection().clear_tracks ();
1202                 } else {
1203                         _editor.select_all_tracks ();
1204                 }
1205
1206                 return;
1207         }
1208
1209         switch (ArdourKeyboard::selection_type (ev->state)) {
1210         case Selection::Toggle:
1211                 _editor.get_selection().toggle (this);
1212                 break;
1213
1214         case Selection::Set:
1215                 _editor.get_selection().set (this);
1216                 break;
1217
1218         case Selection::Extend:
1219                 _editor.extend_selection_to_track (*this);
1220                 break;
1221
1222         case Selection::Add:
1223                 _editor.get_selection().add (this);
1224                 break;
1225         }
1226 }
1227
1228 void
1229 RouteTimeAxisView::set_selected_points (PointSelection& points)
1230 {
1231         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1232                 (*i)->set_selected_points (points);
1233         }
1234 }
1235
1236 void
1237 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1238 {
1239         if (_view) {
1240                 _view->set_selected_regionviews (regions);
1241         }
1242 }
1243
1244 /** Add the selectable things that we have to a list.
1245  * @param results List to add things to.
1246  */
1247 void
1248 RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top, double bot, list<Selectable*>& results)
1249 {
1250         double speed = 1.0;
1251
1252         if (track() != 0) {
1253                 speed = track()->speed();
1254         }
1255
1256         framepos_t const start_adjusted = session_frame_to_track_frame(start, speed);
1257         framepos_t const end_adjusted   = session_frame_to_track_frame(end, speed);
1258
1259         if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1260                 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1261         }
1262
1263         /* pick up visible automation tracks */
1264
1265         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1266                 if (!(*i)->hidden()) {
1267                         (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1268                 }
1269         }
1270 }
1271
1272 void
1273 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1274 {
1275         if (_view) {
1276                 _view->get_inverted_selectables (sel, results);
1277         }
1278
1279         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1280                 if (!(*i)->hidden()) {
1281                         (*i)->get_inverted_selectables (sel, results);
1282                 }
1283         }
1284
1285         return;
1286 }
1287
1288 RouteGroup*
1289 RouteTimeAxisView::route_group () const
1290 {
1291         return _route->route_group();
1292 }
1293
1294 string
1295 RouteTimeAxisView::name() const
1296 {
1297         return _route->name();
1298 }
1299
1300 boost::shared_ptr<Playlist>
1301 RouteTimeAxisView::playlist () const
1302 {
1303         boost::shared_ptr<Track> tr;
1304
1305         if ((tr = track()) != 0) {
1306                 return tr->playlist();
1307         } else {
1308                 return boost::shared_ptr<Playlist> ();
1309         }
1310 }
1311
1312 void
1313 RouteTimeAxisView::name_entry_changed ()
1314 {
1315         string x;
1316
1317         x = name_entry.get_text ();
1318
1319         if (x == _route->name()) {
1320                 return;
1321         }
1322
1323         strip_whitespace_edges(x);
1324
1325         if (x.length() == 0) {
1326                 name_entry.set_text (_route->name());
1327                 return;
1328         }
1329
1330         if (!_session->route_name_unique (x)) {
1331                 ARDOUR_UI::instance()->popup_error (_("A track already exists with that name"));
1332                 name_entry.set_text (_route->name());
1333         } else if (_session->route_name_internal (x)) {
1334                 ARDOUR_UI::instance()->popup_error (string_compose (_("You cannot create a track with that name as it is reserved for %1"),
1335                                                                     PROGRAM_NAME));
1336                 name_entry.set_text (_route->name());
1337         } else {
1338                 _route->set_name (x);
1339         }
1340 }
1341
1342 boost::shared_ptr<Region>
1343 RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir)
1344 {
1345         boost::shared_ptr<Playlist> pl = playlist ();
1346
1347         if (pl) {
1348                 return pl->find_next_region (pos, point, dir);
1349         }
1350
1351         return boost::shared_ptr<Region> ();
1352 }
1353
1354 framepos_t
1355 RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir)
1356 {
1357         boost::shared_ptr<Playlist> pl = playlist ();
1358
1359         if (pl) {
1360                 return pl->find_next_region_boundary (pos, dir);
1361         }
1362
1363         return -1;
1364 }
1365
1366 void
1367 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1368 {
1369         boost::shared_ptr<Playlist> what_we_got;
1370         boost::shared_ptr<Track> tr = track ();
1371         boost::shared_ptr<Playlist> playlist;
1372
1373         if (tr == 0) {
1374                 /* route is a bus, not a track */
1375                 return;
1376         }
1377
1378         playlist = tr->playlist();
1379
1380         TimeSelection time (selection.time);
1381         float const speed = tr->speed();
1382         if (speed != 1.0f) {
1383                 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1384                         (*i).start = session_frame_to_track_frame((*i).start, speed);
1385                         (*i).end   = session_frame_to_track_frame((*i).end,   speed);
1386                 }
1387         }
1388
1389         playlist->clear_changes ();
1390         playlist->clear_owned_changes ();
1391
1392         switch (op) {
1393         case Cut:
1394                 if ((what_we_got = playlist->cut (time)) != 0) {
1395                         _editor.get_cut_buffer().add (what_we_got);
1396
1397                         vector<Command*> cmds;
1398                         playlist->rdiff (cmds);
1399                         _session->add_commands (cmds);
1400                         
1401                         _session->add_command (new StatefulDiffCommand (playlist));
1402                 }
1403                 break;
1404         case Copy:
1405                 if ((what_we_got = playlist->copy (time)) != 0) {
1406                         _editor.get_cut_buffer().add (what_we_got);
1407                 }
1408                 break;
1409
1410         case Clear:
1411                 if ((what_we_got = playlist->cut (time)) != 0) {
1412
1413                         vector<Command*> cmds;
1414                         playlist->rdiff (cmds);
1415                         _session->add_commands (cmds);
1416                         _session->add_command (new StatefulDiffCommand (playlist));
1417                         what_we_got->release ();
1418                 }
1419                 break;
1420         }
1421 }
1422
1423 bool
1424 RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, size_t nth)
1425 {
1426         if (!is_track()) {
1427                 return false;
1428         }
1429
1430         boost::shared_ptr<Playlist> pl = playlist ();
1431         PlaylistSelection::iterator p;
1432
1433         for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth) {}
1434
1435         if (p == selection.playlists.end()) {
1436                 return false;
1437         }
1438
1439         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
1440
1441         if (track()->speed() != 1.0f) {
1442                 pos = session_frame_to_track_frame (pos, track()->speed());
1443                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
1444         }
1445
1446         pl->clear_changes ();
1447         pl->paste (*p, pos, times);
1448         _session->add_command (new StatefulDiffCommand (pl));
1449
1450         return true;
1451 }
1452
1453
1454 struct PlaylistSorter {
1455     bool operator() (boost::shared_ptr<Playlist> a, boost::shared_ptr<Playlist> b) const {
1456             return a->sort_id() < b->sort_id();
1457     }
1458 };
1459
1460 void
1461 RouteTimeAxisView::build_playlist_menu ()
1462 {
1463         using namespace Menu_Helpers;
1464
1465         if (!is_track()) {
1466                 return;
1467         }
1468
1469         delete playlist_action_menu;
1470         playlist_action_menu = new Menu;
1471         playlist_action_menu->set_name ("ArdourContextMenu");
1472
1473         MenuList& playlist_items = playlist_action_menu->items();
1474         playlist_action_menu->set_name ("ArdourContextMenu");
1475         playlist_items.clear();
1476
1477         vector<boost::shared_ptr<Playlist> > playlists, playlists_tr;
1478         boost::shared_ptr<Track> tr = track();
1479         RadioMenuItem::Group playlist_group;
1480
1481         _session->playlists->get (playlists);
1482
1483         /* find the playlists for this diskstream */
1484         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
1485                 if (((*i)->get_orig_diskstream_id() == tr->diskstream_id()) || (tr->playlist()->id() == (*i)->id())) {
1486                         playlists_tr.push_back(*i);
1487                 }
1488         }
1489
1490         /* sort the playlists */
1491         PlaylistSorter cmp;
1492         sort (playlists_tr.begin(), playlists_tr.end(), cmp);
1493         
1494         /* add the playlists to the menu */
1495         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
1496                 playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
1497                 RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
1498                 item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
1499                 
1500                 if (tr->playlist()->id() == (*i)->id()) {
1501                         item->set_active();
1502                         
1503                 }
1504         }
1505         
1506         playlist_items.push_back (SeparatorElem());
1507         playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1508         playlist_items.push_back (SeparatorElem());
1509
1510         if (!route_group() || !route_group()->is_active()) {
1511                 playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1512                 playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1513
1514         } else {
1515                 // Use a label which tells the user what is happening
1516                 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1517                 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1518
1519         }
1520
1521         playlist_items.push_back (SeparatorElem());
1522         playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1523         playlist_items.push_back (SeparatorElem());
1524
1525         playlist_items.push_back (MenuElem(_("Select from all..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1526 }
1527
1528 void
1529 RouteTimeAxisView::use_playlist (RadioMenuItem *item, boost::weak_ptr<Playlist> wpl)
1530 {
1531         assert (is_track());
1532
1533         // exit if we were triggered by deactivating the old playlist
1534         if (!item->get_active()) {
1535                 return;
1536         }
1537
1538         boost::shared_ptr<Playlist> pl (wpl.lock());
1539
1540         if (!pl) {
1541                 return;
1542         }
1543
1544         boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
1545
1546         if (apl) {
1547                 if (track()->playlist() == apl) {
1548                         // exit when use_playlist is called by the creation of the playlist menu
1549                         // or the playlist choice is unchanged
1550                         return;
1551                 }
1552                 track()->use_playlist (apl);
1553
1554                 if (route_group() && route_group()->is_active()) {
1555                         std::string group_string = "."+route_group()->name()+".";
1556
1557                         std::string take_name = apl->name();
1558                         std::string::size_type idx = take_name.find(group_string);
1559
1560                         if (idx == std::string::npos)
1561                                 return;
1562
1563                         take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1564
1565                         boost::shared_ptr<RouteList> rl (route_group()->route_list());
1566
1567                         for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1568                                 if ( (*i) == this->route()) {
1569                                         continue;
1570                                 }
1571
1572                                 std::string playlist_name = (*i)->name()+group_string+take_name;
1573
1574                                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1575                                 if (!track) {
1576                                         continue;
1577                                 }
1578
1579                                 boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
1580                                 if (!ipl) {
1581                                         // No playlist for this track for this take yet, make it
1582                                         track->use_new_playlist();
1583                                         track->playlist()->set_name(playlist_name);
1584                                 } else {
1585                                         track->use_playlist(ipl);
1586                                 }
1587                         }
1588                 }
1589         }
1590 }
1591
1592 void
1593 RouteTimeAxisView::show_playlist_selector ()
1594 {
1595         _editor.playlist_selector().show_for (this);
1596 }
1597
1598 void
1599 RouteTimeAxisView::map_frozen ()
1600 {
1601         if (!is_track()) {
1602                 return;
1603         }
1604
1605         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1606
1607         switch (track()->freeze_state()) {
1608         case Track::Frozen:
1609                 playlist_button.set_sensitive (false);
1610                 rec_enable_button->set_sensitive (false);
1611                 break;
1612         default:
1613                 playlist_button.set_sensitive (true);
1614                 rec_enable_button->set_sensitive (true);
1615                 break;
1616         }
1617 }
1618
1619 void
1620 RouteTimeAxisView::color_handler ()
1621 {
1622         //case cTimeStretchOutline:
1623         if (timestretch_rect) {
1624                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
1625         }
1626         //case cTimeStretchFill:
1627         if (timestretch_rect) {
1628                 timestretch_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
1629         }
1630
1631         reset_meter();
1632 }
1633
1634 /** Toggle an automation track for a fully-specified Parameter (type,channel,id)
1635  *  Will add track if necessary.
1636  */
1637 void
1638 RouteTimeAxisView::toggle_automation_track (const Evoral::Parameter& param)
1639 {
1640         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1641         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1642         
1643         if (!track) {
1644                 /* it doesn't exist yet, so we don't care about the button state: just add it */
1645                 create_automation_child (param, true);
1646         } else {
1647                 assert (menu);
1648                 bool yn = menu->get_active();
1649                 if (track->set_visibility (menu->get_active()) && yn) {
1650                         
1651                         /* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
1652                            will have done that for us.
1653                         */
1654                         
1655                         if (!no_redraw) {
1656                                 _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
1657                         } 
1658                 }
1659         }
1660 }
1661
1662 void
1663 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1664 {
1665         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
1666
1667         if (!track) {
1668                 return;
1669         }
1670
1671         Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
1672
1673         // if Evoral::Parameter::operator< doesn't obey strict weak ordering, we may crash here....
1674         track->get_state_node()->add_property (X_("shown"), X_("no"));
1675
1676         if (menu && !_hidden) {
1677                 ignore_toggle = true;
1678                 menu->set_active (false);
1679                 ignore_toggle = false;
1680         }
1681
1682         if (_route && !no_redraw) {
1683                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1684         }
1685 }
1686
1687
1688 void
1689 RouteTimeAxisView::show_all_automation (bool apply_to_selection)
1690 {
1691         if (apply_to_selection) {
1692                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
1693         } else {
1694                 no_redraw = true;
1695                 
1696                 /* Show our automation */
1697                 
1698                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1699                         i->second->set_marked_for_display (true);
1700                         i->second->canvas_display()->show();
1701                         i->second->get_state_node()->add_property ("shown", X_("yes"));
1702                         
1703                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1704                         
1705                         if (menu) {
1706                                 menu->set_active(true);
1707                         }
1708                 }
1709                 
1710                 
1711                 /* Show processor automation */
1712                 
1713                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1714                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1715                                 if ((*ii)->view == 0) {
1716                                         add_processor_automation_curve ((*i)->processor, (*ii)->what);
1717                                 }
1718                                 
1719                                 (*ii)->menu_item->set_active (true);
1720                         }
1721                 }
1722                 
1723                 no_redraw = false;
1724                 
1725                 /* Redraw */
1726                 
1727                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1728         }
1729 }
1730         
1731 void
1732 RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
1733 {
1734         if (apply_to_selection) {
1735                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
1736         } else {
1737                 no_redraw = true;
1738                 
1739                 /* Show our automation */
1740                 
1741                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1742                         if (i->second->has_automation()) {
1743                                 i->second->set_marked_for_display (true);
1744                                 i->second->canvas_display()->show();
1745                                 i->second->get_state_node()->add_property ("shown", X_("yes"));
1746                                 
1747                                 Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1748                                 if (menu) {
1749                                         menu->set_active(true);
1750                                 }
1751                         }
1752                 }
1753                 
1754                 
1755                 /* Show processor automation */
1756                 
1757                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1758                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1759                                 if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
1760                                         (*ii)->menu_item->set_active (true);
1761                                 }
1762                         }
1763                 }
1764                 
1765                 no_redraw = false;
1766                 
1767                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1768         }
1769 }
1770
1771 void
1772 RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
1773 {
1774         if (apply_to_selection) {
1775                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
1776         } else {
1777                 no_redraw = true;
1778
1779                 /* Hide our automation */
1780                 
1781                 for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1782                         i->second->set_marked_for_display (false);
1783                         i->second->hide ();
1784                         i->second->get_state_node()->add_property ("shown", X_("no"));
1785                         
1786                         Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
1787                         
1788                         if (menu) {
1789                                 menu->set_active (false);
1790                         }
1791                 }
1792                 
1793                 /* Hide processor automation */
1794                 
1795                 for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1796                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1797                                 (*ii)->menu_item->set_active (false);
1798                         }
1799                 }
1800                 
1801                 no_redraw = false;
1802                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1803         }
1804 }
1805
1806
1807 void
1808 RouteTimeAxisView::region_view_added (RegionView* rv)
1809 {
1810         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
1811         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1812                 boost::shared_ptr<AutomationTimeAxisView> atv;
1813                 
1814                 if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1815                         atv->add_ghost(rv);
1816                 }
1817         }
1818
1819         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
1820                 (*i)->add_ghost(rv);
1821         }
1822 }
1823
1824 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1825 {
1826         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1827                 delete *i;
1828         }
1829 }
1830
1831
1832 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1833 {
1834         parent.remove_processor_automation_node (this);
1835 }
1836
1837 void
1838 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1839 {
1840         if (pan->view) {
1841                 remove_child (pan->view);
1842         }
1843 }
1844
1845 RouteTimeAxisView::ProcessorAutomationNode*
1846 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1847 {
1848         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1849
1850                 if ((*i)->processor == processor) {
1851
1852                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1853                                 if ((*ii)->what == what) {
1854                                         return *ii;
1855                                 }
1856                         }
1857                 }
1858         }
1859
1860         return 0;
1861 }
1862
1863 static string
1864 legalize_for_xml_node (string str)
1865 {
1866         string::size_type pos;
1867         string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:";
1868         string legal;
1869
1870         legal = str;
1871         pos = 0;
1872
1873         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
1874                 legal.replace (pos, 1, "_");
1875                 pos += 1;
1876         }
1877
1878         return legal;
1879 }
1880
1881
1882 void
1883 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1884 {
1885         string name;
1886         ProcessorAutomationNode* pan;
1887
1888         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1889                 /* session state may never have been saved with new plugin */
1890                 error << _("programming error: ")
1891                       << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"),
1892                                          processor->name(), what.type(), (int) what.channel(), what.id() )
1893                       << endmsg;
1894                 /*NOTREACHED*/
1895                 return;
1896         }
1897
1898         if (pan->view) {
1899                 return;
1900         }
1901
1902         name = processor->describe_parameter (what);
1903
1904         /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
1905
1906         /* FIXME: ew */
1907
1908         char state_name[256];
1909         snprintf (state_name, sizeof (state_name), "%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id());
1910
1911         boost::shared_ptr<AutomationControl> control
1912                         = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
1913
1914         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
1915                 new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
1916                                             _editor, *this, false, parent_canvas, name, state_name));
1917
1918         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
1919
1920         if (!pan->view->marked_for_display()) {
1921                 pan->view->hide ();
1922         } else {
1923                 pan->menu_item->set_active (true);
1924         }
1925
1926         add_child (pan->view);
1927
1928         if (_view) {
1929                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
1930         }
1931
1932         processor->mark_automation_visible (what, true);
1933 }
1934
1935 void
1936 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor> i)
1937 {
1938         if (!_hidden) {
1939                 pan->menu_item->set_active (false);
1940         }
1941
1942         i->mark_automation_visible (pan->what, false);
1943
1944         if (!no_redraw) {
1945                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1946         }
1947 }
1948
1949 void
1950 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
1951 {
1952         boost::shared_ptr<Processor> processor (p.lock ());
1953         if (!processor) {
1954                 return;
1955         }
1956
1957         set<Evoral::Parameter> s;
1958         boost::shared_ptr<AutomationLine> al;
1959
1960         processor->what_has_visible_data (s);
1961
1962         for (set<Evoral::Parameter>::iterator i = s.begin(); i != s.end(); ++i) {
1963
1964                 if ((al = find_processor_automation_curve (processor, *i)) != 0) {
1965                         al->queue_reset ();
1966                 } else {
1967                         add_processor_automation_curve (processor, (*i));
1968                 }
1969         }
1970 }
1971
1972 void
1973 RouteTimeAxisView::add_automation_child (Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
1974 {
1975         using namespace Menu_Helpers;
1976
1977         XMLProperty* prop;
1978         XMLNode* node;
1979
1980         add_child (track);
1981
1982         track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
1983
1984         bool hideit = (!show);
1985
1986         if ((node = track->get_state_node()) != 0) {
1987                 if  ((prop = node->property ("shown")) != 0) {
1988                         if (string_is_affirmative (prop->value())) {
1989                                 hideit = false;
1990                         }
1991                 }
1992         }
1993
1994         _automation_tracks[param] = track;
1995
1996         track->set_visibility (!hideit);
1997
1998         if (!no_redraw) {
1999                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2000         }
2001
2002         if (!EventTypeMap::instance().is_midi_parameter(param)) {
2003                 /* MIDI-related parameters are always in the menu, there's no
2004                    reason to rebuild the menu just because we added a automation
2005                    lane for one of them. But if we add a non-MIDI automation
2006                    lane, then we need to invalidate the display menu.
2007                 */
2008                 delete display_menu;
2009                 display_menu = 0;
2010         }
2011 }
2012
2013 void
2014 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2015 {
2016         boost::shared_ptr<Processor> processor (p.lock ());
2017
2018         if (!processor || !processor->display_to_user ()) {
2019                 return;
2020         }
2021
2022         using namespace Menu_Helpers;
2023         ProcessorAutomationInfo *rai;
2024         list<ProcessorAutomationInfo*>::iterator x;
2025
2026         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2027         std::set<Evoral::Parameter> has_visible_automation;
2028
2029         processor->what_has_visible_data(has_visible_automation);
2030
2031         if (automatable.empty()) {
2032                 return;
2033         }
2034
2035         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2036                 if ((*x)->processor == processor) {
2037                         break;
2038                 }
2039         }
2040
2041         if (x == processor_automation.end()) {
2042
2043                 rai = new ProcessorAutomationInfo (processor);
2044                 processor_automation.push_back (rai);
2045
2046         } else {
2047
2048                 rai = *x;
2049
2050         }
2051
2052         /* any older menu was deleted at the top of processors_changed()
2053            when we cleared the subplugin menu.
2054         */
2055
2056         rai->menu = manage (new Menu);
2057         MenuList& items = rai->menu->items();
2058         rai->menu->set_name ("ArdourContextMenu");
2059
2060         items.clear ();
2061
2062         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2063
2064                 ProcessorAutomationNode* pan;
2065                 CheckMenuItem* mitem;
2066
2067                 string name = processor->describe_parameter (*i);
2068
2069                 items.push_back (CheckMenuElem (name));
2070                 mitem = dynamic_cast<CheckMenuItem*> (&items.back());
2071
2072                 _subplugin_menu_map[*i] = mitem;
2073
2074                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2075                         mitem->set_active(true);
2076                 }
2077
2078                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2079
2080                         /* new item */
2081
2082                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2083
2084                         rai->lines.push_back (pan);
2085
2086                 } else {
2087
2088                         pan->menu_item = mitem;
2089
2090                 }
2091
2092                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2093         }
2094
2095         /* add the menu for this processor, because the subplugin
2096            menu is always cleared at the top of processors_changed().
2097            this is the result of some poor design in gtkmm and/or
2098            GTK+.
2099         */
2100
2101         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2102         rai->valid = true;
2103 }
2104
2105 void
2106 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2107                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2108 {
2109         bool showit = pan->menu_item->get_active();
2110         bool redraw = false;
2111
2112         if (pan->view == 0 && showit) {
2113                 add_processor_automation_curve (rai->processor, pan->what);
2114                 redraw = true;
2115         }
2116
2117         if (pan->view && showit != pan->view->marked_for_display()) {
2118
2119                 if (showit) {
2120                         pan->view->set_marked_for_display (true);
2121                         pan->view->canvas_display()->show();
2122                         pan->view->canvas_background()->show();
2123                 } else {
2124                         rai->processor->mark_automation_visible (pan->what, true);
2125                         pan->view->set_marked_for_display (false);
2126                         pan->view->hide ();
2127                 }
2128
2129                 redraw = true;
2130
2131         }
2132
2133         if (redraw && !no_redraw) {
2134                  _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2135
2136         }
2137 }
2138
2139 void
2140 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2141 {
2142         if (c.type == RouteProcessorChange::MeterPointChange) {
2143                 /* nothing to do if only the meter point has changed */
2144                 return;
2145         }
2146
2147         using namespace Menu_Helpers;
2148
2149         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2150                 (*i)->valid = false;
2151         }
2152
2153         _subplugin_menu_map.clear ();
2154         subplugin_menu.items().clear ();
2155
2156         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
2157         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
2158
2159         bool deleted_processor_automation = false;
2160
2161         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2162
2163                 list<ProcessorAutomationInfo*>::iterator tmp;
2164
2165                 tmp = i;
2166                 ++tmp;
2167
2168                 if (!(*i)->valid) {
2169
2170                         delete *i;
2171                         processor_automation.erase (i);
2172                         deleted_processor_automation = true;
2173
2174                 }
2175
2176                 i = tmp;
2177         }
2178
2179         if (deleted_processor_automation && !no_redraw) {
2180                 _route->gui_changed ("track_height", this);
2181         }
2182 }
2183
2184 boost::shared_ptr<AutomationLine>
2185 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2186 {
2187         ProcessorAutomationNode* pan;
2188
2189         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2190                 if (pan->view) {
2191                         pan->view->line();
2192                 }
2193         }
2194
2195         return boost::shared_ptr<AutomationLine>();
2196 }
2197
2198 void
2199 RouteTimeAxisView::reset_processor_automation_curves ()
2200 {
2201         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2202                 (*i)->reset();
2203         }
2204 }
2205
2206 void
2207 RouteTimeAxisView::update_rec_display ()
2208 {
2209         RouteUI::update_rec_display ();
2210         name_entry.set_sensitive (!_route->record_enabled());
2211 }
2212
2213 void
2214 RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
2215 {
2216         if (apply_to_selection) {
2217                 _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
2218         } else {
2219                 
2220                 if (_view) {
2221                         _view->set_layer_display (d);
2222                 }
2223                 
2224                 ensure_xml_node ();
2225                 xml_node->add_property (N_("layer-display"), enum_2_string (d));
2226         }
2227 }
2228
2229 LayerDisplay
2230 RouteTimeAxisView::layer_display () const
2231 {
2232         if (_view) {
2233                 return _view->layer_display ();
2234         }
2235
2236         /* we don't know, since we don't have a _view, so just return something */
2237         return Overlaid;
2238 }
2239
2240
2241
2242 boost::shared_ptr<AutomationTimeAxisView>
2243 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2244 {
2245         AutomationTracks::iterator i = _automation_tracks.find(param);
2246         if (i != _automation_tracks.end()) {
2247                 return i->second;
2248         } else {
2249                 return boost::shared_ptr<AutomationTimeAxisView>();
2250         }
2251 }
2252
2253 void
2254 RouteTimeAxisView::fast_update ()
2255 {
2256         gm.get_level_meter().update_meters ();
2257 }
2258
2259 void
2260 RouteTimeAxisView::hide_meter ()
2261 {
2262         clear_meter ();
2263         gm.get_level_meter().hide_meters ();
2264 }
2265
2266 void
2267 RouteTimeAxisView::show_meter ()
2268 {
2269         reset_meter ();
2270 }
2271
2272 void
2273 RouteTimeAxisView::reset_meter ()
2274 {
2275         if (Config->get_show_track_meters()) {
2276                 gm.get_level_meter().setup_meters (height-5);
2277         } else {
2278                 hide_meter ();
2279         }
2280 }
2281
2282 void
2283 RouteTimeAxisView::clear_meter ()
2284 {
2285         gm.get_level_meter().clear_meters ();
2286 }
2287
2288 void
2289 RouteTimeAxisView::meter_changed ()
2290 {
2291         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed)
2292         reset_meter();
2293 }
2294
2295 void
2296 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2297 {
2298         reset_meter ();
2299 }
2300
2301 void
2302 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu)
2303 {
2304         using namespace Menu_Helpers;
2305
2306         if (!_underlay_streams.empty()) {
2307                 MenuList& parent_items = parent_menu->items();
2308                 Menu* gs_menu = manage (new Menu);
2309                 gs_menu->set_name ("ArdourContextMenu");
2310                 MenuList& gs_items = gs_menu->items();
2311
2312                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2313
2314                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2315                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2316                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2317                 }
2318         }
2319 }
2320
2321 bool
2322 RouteTimeAxisView::set_underlay_state()
2323 {
2324         if (!underlay_xml_node) {
2325                 return false;
2326         }
2327
2328         XMLNodeList nlist = underlay_xml_node->children();
2329         XMLNodeConstIterator niter;
2330         XMLNode *child_node;
2331
2332         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2333                 child_node = *niter;
2334
2335                 if (child_node->name() != "Underlay") {
2336                         continue;
2337                 }
2338
2339                 XMLProperty* prop = child_node->property ("id");
2340                 if (prop) {
2341                         PBD::ID id (prop->value());
2342
2343                         RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id);
2344
2345                         if (v) {
2346                                 add_underlay(v->view(), false);
2347                         }
2348                 }
2349         }
2350
2351         return false;
2352 }
2353
2354 void
2355 RouteTimeAxisView::add_underlay (StreamView* v, bool update_xml)
2356 {
2357         if (!v) {
2358                 return;
2359         }
2360
2361         RouteTimeAxisView& other = v->trackview();
2362
2363         if (find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2364                 if (find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2365                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2366                         /*NOTREACHED*/
2367                 }
2368
2369                 _underlay_streams.push_back(v);
2370                 other._underlay_mirrors.push_back(this);
2371
2372                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2373
2374                 if (update_xml) {
2375                         if (!underlay_xml_node) {
2376                                 ensure_xml_node();
2377                                 underlay_xml_node = xml_node->add_child("Underlays");
2378                         }
2379
2380                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2381                         XMLProperty* prop = node->add_property("id");
2382                         prop->set_value(v->trackview().route()->id().to_s());
2383                 }
2384         }
2385 }
2386
2387 void
2388 RouteTimeAxisView::remove_underlay (StreamView* v)
2389 {
2390         if (!v) {
2391                 return;
2392         }
2393
2394         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2395         RouteTimeAxisView& other = v->trackview();
2396
2397         if (it != _underlay_streams.end()) {
2398                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2399
2400                 if (gm == other._underlay_mirrors.end()) {
2401                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2402                         /*NOTREACHED*/
2403                 }
2404
2405                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2406
2407                 _underlay_streams.erase(it);
2408                 other._underlay_mirrors.erase(gm);
2409
2410                 if (underlay_xml_node) {
2411                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2412                 }
2413         }
2414 }
2415
2416 void
2417 RouteTimeAxisView::set_button_names ()
2418 {
2419         rec_enable_button_label.set_text (_("r"));
2420
2421         if (_route && _route->solo_safe()) {
2422                 solo_button_label.set_text (X_("!"));
2423         } else {
2424                 if (Config->get_solo_control_is_listen_control()) {
2425                         switch (Config->get_listen_position()) {
2426                         case AfterFaderListen:
2427                                 solo_button_label.set_text (_("A"));
2428                                 break;
2429                         case PreFaderListen:
2430                                 solo_button_label.set_text (_("P"));
2431                                 break;
2432                         }
2433                 } else {
2434                         solo_button_label.set_text (_("s"));
2435                 }
2436         }
2437         mute_button_label.set_text (_("m"));
2438 }
2439
2440 Gtk::CheckMenuItem*
2441 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
2442 {
2443         ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
2444         if (i != _main_automation_menu_map.end()) {
2445                 return i->second;
2446         }
2447         
2448         i = _subplugin_menu_map.find (param);
2449         if (i != _subplugin_menu_map.end()) {
2450                 return i->second;
2451         }
2452
2453         return 0;
2454 }
2455
2456 void
2457 RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show)
2458 {
2459         boost::shared_ptr<AutomationControl> c = _route->gain_control();
2460         if (!c) {
2461                 error << "Route has no gain automation, unable to add automation track view." << endmsg;
2462                 return;
2463         }
2464
2465         gain_track.reset (new AutomationTimeAxisView (_session,
2466                                                       _route, _route->amp(), c, param,
2467                                                       _editor,
2468                                                       *this,
2469                                                       false,
2470                                                       parent_canvas,
2471                                                       _route->amp()->describe_parameter(param)));
2472
2473         if (_view) {
2474                 _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
2475         }
2476         
2477         add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
2478 }