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