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