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