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