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