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