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