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