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