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