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