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