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