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