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