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