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