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