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