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