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