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