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