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