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