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