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