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