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