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