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