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