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