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