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