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