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