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