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