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