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