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