e46d31bf8d9faa72d99b1d149bdcca20dd1065e0
[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 <utility>
27
28 #include <sigc++/bind.h>
29
30 #include "pbd/error.h"
31 #include "pbd/stl_delete.h"
32 #include "pbd/whitespace.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/enumwriter.h"
35
36 #include <gtkmm/menu.h>
37 #include <gtkmm/menuitem.h>
38 #include <gtkmm2ext/gtk_ui.h>
39 #include <gtkmm2ext/selector.h>
40 #include <gtkmm2ext/stop_signal.h>
41 #include <gtkmm2ext/bindable_button.h>
42 #include <gtkmm2ext/utils.h>
43
44 #include "ardour/amp.h"
45 #include "ardour/audioplaylist.h"
46 #include "ardour/diskstream.h"
47 #include "ardour/event_type_map.h"
48 #include "ardour/ladspa_plugin.h"
49 #include "ardour/location.h"
50 #include "ardour/panner.h"
51 #include "ardour/playlist.h"
52 #include "ardour/playlist.h"
53 #include "ardour/processor.h"
54 #include "ardour/profile.h"
55 #include "ardour/route_group.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlist.h"
58 #include "ardour/debug.h"
59 #include "ardour/utils.h"
60 #include "evoral/Parameter.hpp"
61
62 #include "ardour_ui.h"
63 #include "route_time_axis.h"
64 #include "automation_time_axis.h"
65 #include "canvas_impl.h"
66 #include "crossfade_view.h"
67 #include "enums.h"
68 #include "gui_thread.h"
69 #include "keyboard.h"
70 #include "playlist_selector.h"
71 #include "point_selection.h"
72 #include "prompter.h"
73 #include "public_editor.h"
74 #include "region_view.h"
75 #include "rgb_macros.h"
76 #include "selection.h"
77 #include "simplerect.h"
78 #include "streamview.h"
79 #include "utils.h"
80 #include "route_group_menu.h"
81
82 #include "ardour/track.h"
83
84 #include "i18n.h"
85
86 using namespace ARDOUR;
87 using namespace PBD;
88 using namespace Gtkmm2ext;
89 using namespace Gtk;
90 using namespace Editing;
91 using namespace sigc;
92 using namespace std;
93
94 Glib::RefPtr<Gdk::Pixbuf> RouteTimeAxisView::slider;
95
96 void
97 RouteTimeAxisView::setup_slider_pix ()
98 {
99         if ((slider = ::get_icon ("fader_belt_h")) == 0) {
100                 throw failed_constructor ();
101         }
102 }
103
104 RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
105         : AxisView(sess)
106         , RouteUI(rt, sess)
107         , TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
108         , parent_canvas (canvas)
109         , button_table (3, 3)
110         , route_group_button (_("g"))
111         , playlist_button (_("p"))
112         , size_button (_("h"))
113         , automation_button (_("a"))
114         , visual_button (_("v"))
115         , gm (sess, slider, true, 115)
116 {
117         set_button_names ();
118
119         gm.set_controls (_route, _route->shared_peak_meter(), _route->amp());
120         gm.get_level_meter().set_no_show_all();
121         gm.get_level_meter().setup_meters(50);
122
123         _has_state = true;
124         playlist_menu = 0;
125         playlist_action_menu = 0;
126         automation_action_menu = 0;
127         mode_menu = 0;
128         _view = 0;
129
130         if (!_route->is_hidden()) {
131                 _marked_for_display = true;
132         }
133
134         timestretch_rect = 0;
135         no_redraw = false;
136         destructive_track_mode_item = 0;
137         normal_track_mode_item = 0;
138         non_layered_track_mode_item = 0;
139
140         ignore_toggle = false;
141
142         route_group_button.set_name ("TrackGroupButton");
143         playlist_button.set_name ("TrackPlaylistButton");
144         automation_button.set_name ("TrackAutomationButton");
145         size_button.set_name ("TrackSizeButton");
146         visual_button.set_name ("TrackVisualButton");
147         hide_button.set_name ("TrackRemoveButton");
148
149         route_group_button.unset_flags (Gtk::CAN_FOCUS);
150         playlist_button.unset_flags (Gtk::CAN_FOCUS);
151         automation_button.unset_flags (Gtk::CAN_FOCUS);
152         size_button.unset_flags (Gtk::CAN_FOCUS);
153         visual_button.unset_flags (Gtk::CAN_FOCUS);
154         hide_button.unset_flags (Gtk::CAN_FOCUS);
155
156         hide_button.add (*(manage (new Image (::get_icon("hide")))));
157         hide_button.show_all ();
158
159         route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::edit_click), false);
160         playlist_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click));
161         automation_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click));
162         size_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::size_click), false);
163         visual_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::visual_click));
164         hide_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::hide_click));
165
166         solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
167         solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
168         mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
169         mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
170
171         if (is_track()) {
172
173                 /* use icon */
174
175                 rec_enable_button->remove ();
176
177                 switch (track()->mode()) {
178                 case ARDOUR::Normal:
179                 case ARDOUR::NonLayered:
180                         rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
181                         break;
182                 case ARDOUR::Destructive:
183                         rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
184                         break;
185                 }
186                 rec_enable_button->show_all ();
187
188                 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
189                 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
190                 controls_table.attach (*rec_enable_button, 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
191                 ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record"));
192
193                 rec_enable_button->set_sensitive (_session.writable());
194         }
195
196         controls_hbox.pack_start(gm.get_level_meter(), false, false);
197         _route->meter_change.connect (sigc::mem_fun(*this, &RouteTimeAxisView::meter_changed));
198         _route->input()->changed.connect (sigc::mem_fun(*this, &RouteTimeAxisView::io_changed));
199         _route->output()->changed.connect (sigc::mem_fun(*this, &RouteTimeAxisView::io_changed));
200
201         controls_table.attach (*mute_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
202         controls_table.attach (*solo_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
203
204         controls_table.attach (route_group_button, 7, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
205         controls_table.attach (gm.get_gain_slider(), 0, 5, 1, 2, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
206
207         ARDOUR_UI::instance()->tooltips().set_tip(*solo_button,_("Solo"));
208         ARDOUR_UI::instance()->tooltips().set_tip(*mute_button,_("Mute"));
209         ARDOUR_UI::instance()->tooltips().set_tip(route_group_button, _("Route Group"));
210         ARDOUR_UI::instance()->tooltips().set_tip(size_button,_("Display Height"));
211         ARDOUR_UI::instance()->tooltips().set_tip(playlist_button,_("Playlist"));
212         ARDOUR_UI::instance()->tooltips().set_tip(automation_button, _("Automation"));
213         ARDOUR_UI::instance()->tooltips().set_tip(visual_button, _("Visual options"));
214         ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("Hide this track"));
215
216         label_view ();
217
218         if (0) {
219
220                 /* old school - when we used to put an extra row of buttons in place */
221
222                 controls_table.attach (hide_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
223                 controls_table.attach (visual_button, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
224                 controls_table.attach (size_button, 2, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
225                 controls_table.attach (automation_button, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
226
227         } else {
228
229                 controls_table.attach (automation_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
230         }
231
232         if (is_track() && track()->mode() == ARDOUR::Normal) {
233                 controls_table.attach (playlist_button, 5, 6, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
234         }
235
236         _y_position = -1;
237
238         _route->mute_changed.connect (sigc::mem_fun(*this, &RouteUI::mute_changed));
239         _route->solo_changed.connect (sigc::mem_fun(*this, &RouteUI::solo_changed));
240         _route->processors_changed.connect (sigc::mem_fun(*this, &RouteTimeAxisView::processors_changed));
241         _route->NameChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_name_changed));
242         _route->solo_isolated_changed.connect (sigc::mem_fun(*this, &RouteUI::solo_changed));
243
244
245         if (is_track()) {
246
247                 track()->TrackModeChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::track_mode_changed));
248                 track()->FreezeChange.connect (sigc::mem_fun(*this, &RouteTimeAxisView::map_frozen));
249                 track()->DiskstreamChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::diskstream_changed));
250                 get_diskstream()->SpeedChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::speed_changed));
251
252                 /* pick up the correct freeze state */
253                 map_frozen ();
254
255         }
256
257         _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit));
258         ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
259
260         route_group_menu = new RouteGroupMenu (
261                 _session,
262                 (RouteGroup::Property) (RouteGroup::Mute | RouteGroup::Solo | RouteGroup::Edit)
263                 );
264
265         route_group_menu->GroupSelected.connect (sigc::mem_fun (*this, &RouteTimeAxisView::set_route_group_from_menu));
266
267         gm.get_gain_slider().signal_scroll_event().connect(sigc::mem_fun(*this, &RouteTimeAxisView::controls_ebox_scroll), false);
268         gm.get_gain_slider().set_name ("TrackGainFader");
269 }
270
271 RouteTimeAxisView::~RouteTimeAxisView ()
272 {
273         GoingAway (); /* EMIT_SIGNAL */
274
275         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
276                 delete *i;
277         }
278
279         delete playlist_menu;
280         playlist_menu = 0;
281
282         delete playlist_action_menu;
283         playlist_action_menu = 0;
284
285         delete _view;
286         _view = 0;
287
288         for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
289                 delete i->second;
290         }
291
292         _automation_tracks.clear ();
293
294         delete route_group_menu;
295 }
296
297 void
298 RouteTimeAxisView::post_construct ()
299 {
300         /* map current state of the route */
301
302         update_diskstream_display ();
303
304         subplugin_menu.items().clear ();
305         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
306         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
307         reset_processor_automation_curves ();
308 }
309
310 gint
311 RouteTimeAxisView::edit_click (GdkEventButton *ev)
312 {
313         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
314                 if (_route->route_group()) {
315                         _route->route_group()->remove (_route);
316                 }
317                 return false;
318         }
319
320         route_group_menu->rebuild (_route->route_group ());
321         route_group_menu->popup (ev->button, ev->time);
322
323         return false;
324 }
325
326 void
327 RouteTimeAxisView::set_route_group_from_menu (RouteGroup *eg)
328 {
329         if (eg) {
330                 eg->add (_route);
331         } else {
332                 if (_route->route_group()) {
333                         _route->route_group()->remove (_route);
334                 }
335         }
336 }
337
338 void
339 RouteTimeAxisView::playlist_changed ()
340 {
341         label_view ();
342 }
343
344 void
345 RouteTimeAxisView::label_view ()
346 {
347         string x = _route->name();
348
349         if (x != name_entry.get_text()) {
350                 name_entry.set_text (x);
351         }
352
353         ARDOUR_UI::instance()->tooltips().set_tip (name_entry, x);
354 }
355
356 void
357 RouteTimeAxisView::route_name_changed ()
358 {
359         label_view ();
360 }
361
362 void
363 RouteTimeAxisView::take_name_changed (void *src)
364
365 {
366         if (src != this) {
367                 label_view ();
368         }
369 }
370
371 void
372 RouteTimeAxisView::playlist_click ()
373 {
374         // always build a new action menu
375
376         delete playlist_action_menu;
377
378         playlist_action_menu = new Menu;
379         playlist_action_menu->set_name ("ArdourContextMenu");
380
381         build_playlist_menu (playlist_action_menu);
382
383         conditionally_add_to_selection ();
384         playlist_action_menu->popup (1, gtk_get_current_event_time());
385 }
386
387 void
388 RouteTimeAxisView::automation_click ()
389 {
390         conditionally_add_to_selection ();
391         build_automation_action_menu ();
392         automation_action_menu->popup (1, gtk_get_current_event_time());
393 }
394
395 int
396 RouteTimeAxisView::set_state (const XMLNode& node, int version)
397 {
398         TimeAxisView::set_state (node, version);
399
400         XMLNodeList kids = node.children();
401         XMLNodeConstIterator iter;
402         const XMLProperty* prop;
403
404         if (_view && (prop = node.property ("layer-display"))) {
405                 set_layer_display (LayerDisplay (string_2_enum (prop->value(), _view->layer_display ())));
406         }
407
408         for (iter = kids.begin(); iter != kids.end(); ++iter) {
409                 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
410                         if ((prop = (*iter)->property ("automation-id")) != 0) {
411
412                                 Evoral::Parameter param = ARDOUR::EventTypeMap::instance().new_parameter(prop->value());
413                                 bool show = ((prop = (*iter)->property ("shown")) != 0) && string_is_affirmative (prop->value());
414                                 create_automation_child(param, show);
415                         } else {
416                                 warning << "Automation child has no ID" << endmsg;
417                         }
418                 }
419         }
420
421         return 0;
422 }
423
424 void
425 RouteTimeAxisView::build_automation_action_menu ()
426 {
427         using namespace Menu_Helpers;
428
429         automation_action_menu = manage (new Menu);
430         MenuList& automation_items = automation_action_menu->items();
431         automation_action_menu->set_name ("ArdourContextMenu");
432
433         automation_items.push_back (MenuElem (_("Show all automation"),
434                                               sigc::mem_fun(*this, &RouteTimeAxisView::show_all_automation)));
435
436         automation_items.push_back (MenuElem (_("Show existing automation"),
437                                               sigc::mem_fun(*this, &RouteTimeAxisView::show_existing_automation)));
438
439         automation_items.push_back (MenuElem (_("Hide all automation"),
440                                               sigc::mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
441
442         if (subplugin_menu.get_attach_widget())
443                 subplugin_menu.detach();
444
445         automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu));
446         automation_items.back().set_sensitive (!subplugin_menu.items().empty());
447
448         map<Evoral::Parameter, RouteAutomationNode*>::iterator i;
449         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
450
451                 automation_items.push_back (SeparatorElem());
452
453                 delete i->second->menu_item;
454
455                 automation_items.push_back(CheckMenuElem (_route->describe_parameter(i->second->param),
456                                 sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::toggle_automation_track), i->second->param)));
457
458                 i->second->menu_item = static_cast<Gtk::CheckMenuItem*>(&automation_items.back());
459
460                 i->second->menu_item->set_active(show_automation(i->second->param));
461                 //i->second->menu_item->set_active(false);
462         }
463 }
464
465 void
466 RouteTimeAxisView::build_display_menu ()
467 {
468         using namespace Menu_Helpers;
469
470         /* get the size menu ready */
471
472         build_size_menu ();
473
474         /* prepare it */
475
476         TimeAxisView::build_display_menu ();
477
478         /* now fill it with our stuff */
479
480         MenuList& items = display_menu->items();
481         display_menu->set_name ("ArdourContextMenu");
482
483         items.push_back (MenuElem (_("Height"), *size_menu));
484         items.push_back (MenuElem (_("Color"), sigc::mem_fun(*this, &RouteTimeAxisView::select_track_color)));
485
486         items.push_back (SeparatorElem());
487
488         if (!Profile->get_sae()) {
489                 items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
490                 /* rebuild this every time */
491                 build_automation_action_menu ();
492                 items.push_back (MenuElem (_("Automation"), *automation_action_menu));
493                 items.push_back (SeparatorElem());
494         }
495
496         // Hook for derived classes to add type specific stuff
497         append_extra_display_menu_items ();
498         items.push_back (SeparatorElem());
499
500         if (is_track()) {
501
502                 Menu *layers_menu = manage(new Menu);
503                 MenuList &layers_items = layers_menu->items();
504                 layers_menu->set_name("ArdourContextMenu");
505
506                 RadioMenuItem::Group layers_group;
507
508                 layers_items.push_back(RadioMenuElem (layers_group, _("Overlaid"),
509                                 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid)));
510                 layers_items.push_back(RadioMenuElem (layers_group, _("Stacked"),
511                                 sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked)));
512
513                 items.push_back (MenuElem (_("Layers"), *layers_menu));
514
515                 Menu* alignment_menu = manage (new Menu);
516                 MenuList& alignment_items = alignment_menu->items();
517                 alignment_menu->set_name ("ArdourContextMenu");
518
519                 RadioMenuItem::Group align_group;
520
521                 alignment_items.push_back (RadioMenuElem (align_group, _("Align with existing material"),
522                                         sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial)));
523                 align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
524                 if (get_diskstream()->alignment_style() == ExistingMaterial)
525                         align_existing_item->set_active();
526
527                 alignment_items.push_back (RadioMenuElem (align_group, _("Align with capture time"),
528                                         sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime)));
529                 align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
530                 if (get_diskstream()->alignment_style() == CaptureTime)
531                         align_capture_item->set_active();
532
533                 if (!Profile->get_sae()) {
534                         items.push_back (MenuElem (_("Alignment"), *alignment_menu));
535                         get_diskstream()->AlignmentStyleChanged.connect (
536                                         sigc::mem_fun(*this, &RouteTimeAxisView::align_style_changed));
537
538                         RadioMenuItem::Group mode_group;
539                         items.push_back (RadioMenuElem (mode_group, _("Normal mode"), sigc::bind (
540                                         sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode),
541                                         ARDOUR::Normal)));
542                         normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
543
544                         items.push_back (RadioMenuElem (mode_group, _("Tape mode"), sigc::bind (
545                                         sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode),
546                                         ARDOUR::Destructive)));
547                         destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
548
549                         items.push_back (RadioMenuElem (mode_group, _("No layering mode"),
550                                                         sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered)));
551                         non_layered_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
552
553
554
555                         switch (track()->mode()) {
556                         case ARDOUR::Destructive:
557                                 destructive_track_mode_item->set_active ();
558                                 break;
559                         case ARDOUR::Normal:
560                                 normal_track_mode_item->set_active ();
561                                 break;
562                         case ARDOUR::NonLayered:
563                                 non_layered_track_mode_item->set_active ();
564                                 break;
565                         }
566                 }
567
568                 get_diskstream()->AlignmentStyleChanged.connect (
569                                 sigc::mem_fun(*this, &RouteTimeAxisView::align_style_changed));
570
571                 mode_menu = build_mode_menu();
572                 if (mode_menu)
573                         items.push_back (MenuElem (_("Mode"), *mode_menu));
574
575                 color_mode_menu = build_color_mode_menu();
576                 if (color_mode_menu)
577                         items.push_back (MenuElem (_("Color Mode"), *color_mode_menu));
578
579                 items.push_back (SeparatorElem());
580         }
581
582         items.push_back (CheckMenuElem (_("Active"), sigc::mem_fun(*this, &RouteUI::toggle_route_active)));
583         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
584         route_active_menu_item->set_active (_route->active());
585
586         items.push_back (SeparatorElem());
587         items.push_back (MenuElem (_("Hide"), sigc::mem_fun(*this, &RouteTimeAxisView::hide_click)));
588         if (!Profile->get_sae()) {
589                 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &RouteUI::remove_this_route)));
590         } else {
591                 items.push_front (SeparatorElem());
592                 items.push_front (MenuElem (_("Delete"), sigc::mem_fun(*this, &RouteUI::remove_this_route)));
593         }
594 }
595
596 static bool __reset_item (RadioMenuItem* item, RadioMenuItem* item_2)
597 {
598         item->set_active ();
599         item_2->set_active ();
600         return false;
601 }
602
603 void
604 RouteTimeAxisView::set_track_mode (TrackMode mode)
605 {
606         RadioMenuItem* item;
607         RadioMenuItem* other_item;
608         RadioMenuItem* other_item_2;
609
610         switch (mode) {
611         case ARDOUR::Normal:
612                 item = normal_track_mode_item;
613                 other_item = non_layered_track_mode_item;
614                 other_item_2 = destructive_track_mode_item;
615                 break;
616         case ARDOUR::NonLayered:
617                 item = non_layered_track_mode_item;
618                 other_item = normal_track_mode_item;
619                 other_item_2 = destructive_track_mode_item;
620                 break;
621         case ARDOUR::Destructive:
622                 item = destructive_track_mode_item;
623                 other_item = normal_track_mode_item;
624                 other_item_2 = non_layered_track_mode_item;
625                 break;
626         default:
627                 fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", mode) << endmsg;
628                 /*NOTREACHED*/
629                 return;
630         }
631
632         if (item && other_item && other_item_2 && item->get_active() && track()->mode() != mode) {
633                 _set_track_mode (track().get(), mode, other_item, other_item_2);
634         }
635 }
636
637 void
638 RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem* reset_item, RadioMenuItem* reset_item_2)
639 {
640         bool needs_bounce;
641
642         if (!track->can_use_mode (mode, needs_bounce)) {
643
644                 if (!needs_bounce) {
645                         /* cannot be done */
646                         Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (__reset_item), reset_item, reset_item_2));
647                         return;
648                 } else {
649                         cerr << "would bounce this one\n";
650                         return;
651                 }
652         }
653
654         track->set_mode (mode);
655
656         rec_enable_button->remove ();
657
658         switch (mode) {
659         case ARDOUR::NonLayered:
660         case ARDOUR::Normal:
661                 rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
662                 break;
663         case ARDOUR::Destructive:
664                 rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
665                 break;
666         }
667
668         rec_enable_button->show_all ();
669 }
670
671 void
672 RouteTimeAxisView::track_mode_changed ()
673 {
674         RadioMenuItem* item;
675
676         switch (track()->mode()) {
677         case ARDOUR::Normal:
678                 item = normal_track_mode_item;
679                 break;
680         case ARDOUR::NonLayered:
681                 item = non_layered_track_mode_item;
682                 break;
683         case ARDOUR::Destructive:
684                 item = destructive_track_mode_item;
685                 break;
686         default:
687                 fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", track()->mode()) << endmsg;
688                 /*NOTREACHED*/
689                 return;
690         }
691
692         item->set_active ();
693 }
694
695 void
696 RouteTimeAxisView::show_timestretch (nframes_t start, nframes_t end)
697 {
698         double x1;
699         double x2;
700         double y2;
701
702         TimeAxisView::show_timestretch (start, end);
703
704         hide_timestretch ();
705
706 #if 0
707         if (ts.empty()) {
708                 return;
709         }
710
711
712         /* check that the time selection was made in our route, or our route group.
713            remember that route_group() == 0 implies the route is *not* in a edit group.
714         */
715
716         if (!(ts.track == this || (ts.group != 0 && ts.group == _route->route_group()))) {
717                 /* this doesn't apply to us */
718                 return;
719         }
720
721         /* ignore it if our edit group is not active */
722
723         if ((ts.track != this) && _route->route_group() && !_route->route_group()->is_active()) {
724                 return;
725         }
726 #endif
727
728         if (timestretch_rect == 0) {
729                 timestretch_rect = new SimpleRect (*canvas_display ());
730                 timestretch_rect->property_x1() =  0.0;
731                 timestretch_rect->property_y1() =  0.0;
732                 timestretch_rect->property_x2() =  0.0;
733                 timestretch_rect->property_y2() =  0.0;
734                 timestretch_rect->property_fill_color_rgba() =  ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
735                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
736         }
737
738         timestretch_rect->show ();
739         timestretch_rect->raise_to_top ();
740
741         x1 = start / _editor.get_current_zoom();
742         x2 = (end - 1) / _editor.get_current_zoom();
743         y2 = current_height() - 2;
744
745         timestretch_rect->property_x1() = x1;
746         timestretch_rect->property_y1() = 1.0;
747         timestretch_rect->property_x2() = x2;
748         timestretch_rect->property_y2() = y2;
749 }
750
751 void
752 RouteTimeAxisView::hide_timestretch ()
753 {
754         TimeAxisView::hide_timestretch ();
755
756         if (timestretch_rect) {
757                 timestretch_rect->hide ();
758         }
759 }
760
761 void
762 RouteTimeAxisView::show_selection (TimeSelection& ts)
763 {
764
765 #if 0
766         /* ignore it if our edit group is not active or if the selection was started
767            in some other track or route group (remember that route_group() == 0 means
768            that the track is not in an route group).
769         */
770
771         if (((ts.track != this && !is_child (ts.track)) && _route->route_group() && !_route->route_group()->is_active()) ||
772             (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route->route_group())))) {
773                 hide_selection ();
774                 return;
775         }
776 #endif
777
778         TimeAxisView::show_selection (ts);
779 }
780
781 void
782 RouteTimeAxisView::set_height (uint32_t h)
783 {
784         int gmlen = h - 5;
785         bool height_changed = (height == 0) || (h != height);
786         gm.get_level_meter().setup_meters (gmlen);
787
788         TimeAxisView::set_height (h);
789
790         ensure_xml_node ();
791
792         if (_view) {
793                 _view->set_height ((double) current_height());
794         }
795
796         char buf[32];
797         snprintf (buf, sizeof (buf), "%u", height);
798         xml_node->add_property ("height", buf);
799
800         if (height >= hNormal) {
801                 reset_meter();
802                 show_name_entry ();
803                 hide_name_label ();
804
805                 gm.get_gain_slider().show();
806                 mute_button->show();
807                 if (!_route || _route->is_control()) {
808                         solo_button->hide();
809                 } else {
810                         solo_button->show();
811                 }
812                 if (rec_enable_button)
813                         rec_enable_button->show();
814
815                 route_group_button.show();
816                 hide_button.show();
817                 visual_button.show();
818                 size_button.show();
819                 automation_button.show();
820
821                 if (is_track() && track()->mode() == ARDOUR::Normal) {
822                         playlist_button.show();
823                 }
824
825         } else if (height >= hSmaller) {
826
827                 reset_meter();
828                 show_name_entry ();
829                 hide_name_label ();
830
831                 gm.get_gain_slider().hide();
832                 mute_button->show();
833                 if (!_route || _route->is_control()) {
834                         solo_button->hide();
835                 } else {
836                         solo_button->show();
837                 }
838                 if (rec_enable_button)
839                         rec_enable_button->show();
840
841                 route_group_button.hide ();
842                 hide_button.hide ();
843                 visual_button.hide ();
844                 size_button.hide ();
845                 automation_button.hide ();
846
847                 if (is_track() && track()->mode() == ARDOUR::Normal) {
848                         playlist_button.hide ();
849                 }
850
851         } else {
852
853
854                 /* don't allow name_entry to be hidden while
855                    it has focus, otherwise the GUI becomes unusable.
856                 */
857
858                 if (name_entry.has_focus()) {
859                         if (name_entry.get_text() != _route->name()) {
860                                 name_entry_changed ();
861                         }
862                         controls_ebox.grab_focus ();
863                 }
864
865                 hide_name_entry ();
866                 show_name_label ();
867
868                 gm.get_gain_slider().hide();
869                 mute_button->hide();
870                 solo_button->hide();
871                 if (rec_enable_button)
872                         rec_enable_button->hide();
873
874                 route_group_button.hide ();
875                 hide_button.hide ();
876                 visual_button.hide ();
877                 size_button.hide ();
878                 automation_button.hide ();
879                 playlist_button.hide ();
880                 name_label.set_text (_route->name());
881         }
882
883         if (height_changed) {
884                 /* only emit the signal if the height really changed */
885                  _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
886         }
887 }
888
889 void
890 RouteTimeAxisView::select_track_color ()
891 {
892         if (RouteUI::choose_color ()) {
893
894                 if (_view) {
895                         _view->apply_color (_color, StreamView::RegionColor);
896                 }
897         }
898 }
899
900 void
901 RouteTimeAxisView::reset_samples_per_unit ()
902 {
903         set_samples_per_unit (_editor.get_current_zoom());
904 }
905
906 void
907 RouteTimeAxisView::set_samples_per_unit (double spu)
908 {
909         double speed = 1.0;
910
911         if (get_diskstream() != 0) {
912                 speed = get_diskstream()->speed();
913         }
914
915         if (_view) {
916                 _view->set_samples_per_unit (spu * speed);
917         }
918
919         TimeAxisView::set_samples_per_unit (spu * speed);
920 }
921
922 void
923 RouteTimeAxisView::align_style_changed ()
924 {
925         switch (get_diskstream()->alignment_style()) {
926         case ExistingMaterial:
927                 if (!align_existing_item->get_active()) {
928                         align_existing_item->set_active();
929                 }
930                 break;
931         case CaptureTime:
932                 if (!align_capture_item->get_active()) {
933                         align_capture_item->set_active();
934                 }
935                 break;
936         }
937 }
938
939 void
940 RouteTimeAxisView::set_align_style (AlignStyle style)
941 {
942         RadioMenuItem* item;
943
944         switch (style) {
945         case ExistingMaterial:
946                 item = align_existing_item;
947                 break;
948         case CaptureTime:
949                 item = align_capture_item;
950                 break;
951         default:
952                 fatal << string_compose (_("programming error: %1 %2"), "illegal align style in RouteTimeAxisView::set_align_style", style) << endmsg;
953                 /*NOTREACHED*/
954                 return;
955         }
956
957         if (item->get_active()) {
958                 get_diskstream()->set_align_style (style);
959         }
960 }
961
962 void
963 RouteTimeAxisView::rename_current_playlist ()
964 {
965         ArdourPrompter prompter (true);
966         string name;
967
968         boost::shared_ptr<Diskstream> ds = get_diskstream();
969         if (!ds || ds->destructive())
970                 return;
971
972         boost::shared_ptr<Playlist> pl = ds->playlist();
973         if (!pl)
974                 return;
975
976         prompter.set_prompt (_("Name for playlist"));
977         prompter.set_initial_text (pl->name());
978         prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
979         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
980
981         switch (prompter.run ()) {
982         case Gtk::RESPONSE_ACCEPT:
983                 prompter.get_result (name);
984                 if (name.length()) {
985                         pl->set_name (name);
986                 }
987                 break;
988
989         default:
990                 break;
991         }
992 }
993
994 std::string
995 RouteTimeAxisView::resolve_new_group_playlist_name(std::string &basename, vector<boost::shared_ptr<Playlist> > const & playlists)
996 {
997         std::string ret (basename);
998
999         std::string const group_string = "." + route_group()->name() + ".";
1000
1001         // iterate through all playlists
1002         int maxnumber = 0;
1003         for (vector<boost::shared_ptr<Playlist> >::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1004                 std::string tmp = (*i)->name();
1005
1006                 std::string::size_type idx = tmp.find(group_string);
1007                 // find those which belong to this group
1008                 if (idx != string::npos) {
1009                         tmp = tmp.substr(idx + group_string.length());
1010
1011                         // and find the largest current number
1012                         int x = atoi(tmp.c_str());
1013                         if (x > maxnumber) {
1014                                 maxnumber = x;
1015                         }
1016                 }
1017         }
1018
1019         maxnumber++;
1020
1021         char buf[32];
1022         snprintf (buf, sizeof(buf), "%d", maxnumber);
1023
1024         ret = this->name() + "." + route_group()->name () + "." + buf;
1025
1026         return ret;
1027 }
1028
1029 void
1030 RouteTimeAxisView::use_copy_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1031 {
1032         string name;
1033
1034         boost::shared_ptr<Diskstream> ds = get_diskstream();
1035         if (!ds || ds->destructive())
1036                 return;
1037
1038         boost::shared_ptr<const Playlist> pl = ds->playlist();
1039         if (!pl)
1040                 return;
1041
1042         name = pl->name();
1043
1044         if (route_group() && route_group()->is_active()) {
1045                 name = resolve_new_group_playlist_name(name, playlists_before_op);
1046         }
1047
1048         while (_session.playlists->by_name(name)) {
1049                 name = Playlist::bump_name (name, _session);
1050         }
1051
1052         // TODO: The prompter "new" button should be de-activated if the user
1053         // specifies a playlist name which already exists in the session.
1054
1055         if (prompt) {
1056
1057                 ArdourPrompter prompter (true);
1058
1059                 prompter.set_prompt (_("Name for Playlist"));
1060                 prompter.set_initial_text (name);
1061                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1062                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1063                 prompter.show_all ();
1064
1065                 switch (prompter.run ()) {
1066                 case Gtk::RESPONSE_ACCEPT:
1067                         prompter.get_result (name);
1068                         break;
1069
1070                 default:
1071                         return;
1072                 }
1073         }
1074
1075         if (name.length()) {
1076                 ds->use_copy_playlist ();
1077                 ds->playlist()->set_name (name);
1078         }
1079 }
1080
1081 void
1082 RouteTimeAxisView::use_new_playlist (bool prompt, vector<boost::shared_ptr<Playlist> > const & playlists_before_op)
1083 {
1084         string name;
1085
1086         boost::shared_ptr<Diskstream> ds = get_diskstream();
1087         if (!ds || ds->destructive())
1088                 return;
1089
1090         boost::shared_ptr<const Playlist> pl = ds->playlist();
1091         if (!pl)
1092                 return;
1093
1094         name = pl->name();
1095
1096         if (route_group() && route_group()->is_active()) {
1097                 name = resolve_new_group_playlist_name(name,playlists_before_op);
1098         }
1099
1100         while (_session.playlists->by_name(name)) {
1101                 name = Playlist::bump_name (name, _session);
1102         }
1103
1104
1105         if (prompt) {
1106
1107                 ArdourPrompter prompter (true);
1108
1109                 prompter.set_prompt (_("Name for Playlist"));
1110                 prompter.set_initial_text (name);
1111                 prompter.add_button (Gtk::Stock::NEW, Gtk::RESPONSE_ACCEPT);
1112                 prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, true);
1113
1114                 switch (prompter.run ()) {
1115                 case Gtk::RESPONSE_ACCEPT:
1116                         prompter.get_result (name);
1117                         break;
1118
1119                 default:
1120                         return;
1121                 }
1122         }
1123
1124         if (name.length()) {
1125                 ds->use_new_playlist ();
1126                 ds->playlist()->set_name (name);
1127         }
1128 }
1129
1130 void
1131 RouteTimeAxisView::clear_playlist ()
1132 {
1133         boost::shared_ptr<Diskstream> ds = get_diskstream();
1134         if (!ds || ds->destructive())
1135                 return;
1136
1137         boost::shared_ptr<Playlist> pl = ds->playlist();
1138         if (!pl)
1139                 return;
1140
1141         _editor.clear_playlist (pl);
1142 }
1143
1144 void
1145 RouteTimeAxisView::speed_changed ()
1146 {
1147         Gtkmm2ext::UI::instance()->call_slot (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit));
1148 }
1149
1150 void
1151 RouteTimeAxisView::diskstream_changed ()
1152 {
1153         Gtkmm2ext::UI::instance()->call_slot (sigc::mem_fun(*this, &RouteTimeAxisView::update_diskstream_display));
1154 }
1155
1156 void
1157 RouteTimeAxisView::update_diskstream_display ()
1158 {
1159         if (!get_diskstream()) // bus
1160                 return;
1161
1162         map_frozen ();
1163 }
1164
1165 void
1166 RouteTimeAxisView::selection_click (GdkEventButton* ev)
1167 {
1168         if (Keyboard::modifier_state_equals (ev->state, (Keyboard::TertiaryModifier|Keyboard::PrimaryModifier))) {
1169
1170                 /* special case: select/deselect all tracks */
1171                 if (_editor.get_selection().selected (this)) {
1172                         _editor.get_selection().clear_tracks ();
1173                 } else {
1174                         _editor.select_all_tracks ();
1175                 }
1176
1177                 return;
1178         }
1179
1180         PublicEditor::TrackViewList* tracks = _editor.get_valid_views (this, _route->route_group());
1181
1182         switch (ArdourKeyboard::selection_type (ev->state)) {
1183         case Selection::Toggle:
1184                 _editor.get_selection().toggle (*tracks);
1185                 break;
1186
1187         case Selection::Set:
1188                 _editor.get_selection().set (*tracks);
1189                 break;
1190
1191         case Selection::Extend:
1192                 if (tracks->size() > 1) {
1193                         /* add each one, do not "extend" */
1194                         _editor.get_selection().add (*tracks);
1195                 } else {
1196                         /* extend to the single track */
1197                         _editor.extend_selection_to_track (*tracks->front());
1198                 }
1199                 break;
1200
1201         case Selection::Add:
1202                 _editor.get_selection().add (*tracks);
1203                 break;
1204         }
1205
1206         delete tracks;
1207 }
1208
1209 void
1210 RouteTimeAxisView::set_selected_points (PointSelection& points)
1211 {
1212         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1213                 (*i)->set_selected_points (points);
1214         }
1215 }
1216
1217 void
1218 RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
1219 {
1220         if (_view) {
1221                 _view->set_selected_regionviews (regions);
1222         }
1223 }
1224
1225 /** Add the selectable things that we have to a list.
1226  * @param results List to add things to.
1227  */
1228 void
1229 RouteTimeAxisView::get_selectables (nframes_t start, nframes_t end, double top, double bot, list<Selectable*>& results)
1230 {
1231         double speed = 1.0;
1232
1233         if (get_diskstream() != 0) {
1234                 speed = get_diskstream()->speed();
1235         }
1236
1237         nframes_t start_adjusted = session_frame_to_track_frame(start, speed);
1238         nframes_t end_adjusted   = session_frame_to_track_frame(end, speed);
1239
1240         if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) {
1241                 _view->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1242         }
1243
1244         /* pick up visible automation tracks */
1245
1246         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1247                 if (!(*i)->hidden()) {
1248                         (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1249                 }
1250         }
1251 }
1252
1253 void
1254 RouteTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1255 {
1256         if (_view) {
1257                 _view->get_inverted_selectables (sel, results);
1258         }
1259
1260         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1261                 if (!(*i)->hidden()) {
1262                         (*i)->get_inverted_selectables (sel, results);
1263                 }
1264         }
1265
1266         return;
1267 }
1268
1269 bool
1270 RouteTimeAxisView::show_automation(Evoral::Parameter param)
1271 {
1272         return (_show_automation.find(param) != _show_automation.end());
1273 }
1274
1275 /** Retuns 0 if track for \a param doesn't exist.
1276  */
1277 RouteTimeAxisView::RouteAutomationNode*
1278 RouteTimeAxisView::automation_track (Evoral::Parameter param)
1279 {
1280         map<Evoral::Parameter, RouteAutomationNode*>::iterator i = _automation_tracks.find (param);
1281
1282         if (i != _automation_tracks.end()) {
1283                 return i->second;
1284         } else {
1285                 return 0;
1286         }
1287 }
1288
1289 /** Shorthand for GainAutomation, etc.
1290  */
1291 RouteTimeAxisView::RouteAutomationNode*
1292 RouteTimeAxisView::automation_track (AutomationType type)
1293 {
1294         return automation_track (Evoral::Parameter(type));
1295 }
1296
1297 RouteGroup*
1298 RouteTimeAxisView::route_group () const
1299 {
1300         return _route->route_group();
1301 }
1302
1303 string
1304 RouteTimeAxisView::name() const
1305 {
1306         return _route->name();
1307 }
1308
1309 boost::shared_ptr<Playlist>
1310 RouteTimeAxisView::playlist () const
1311 {
1312         boost::shared_ptr<Diskstream> ds;
1313
1314         if ((ds = get_diskstream()) != 0) {
1315                 return ds->playlist();
1316         } else {
1317                 return boost::shared_ptr<Playlist> ();
1318         }
1319 }
1320
1321 void
1322 RouteTimeAxisView::name_entry_changed ()
1323 {
1324         string x;
1325
1326         x = name_entry.get_text ();
1327
1328         if (x == _route->name()) {
1329                 return;
1330         }
1331
1332         strip_whitespace_edges(x);
1333
1334         if (x.length() == 0) {
1335                 name_entry.set_text (_route->name());
1336                 return;
1337         }
1338
1339         if (!_session.route_name_unique (x)) {
1340                 ARDOUR_UI::instance()->popup_error (_("A track already exists with that name"));
1341                 name_entry.set_text (_route->name());
1342         } else if (_session.route_name_internal (x)) {
1343                 ARDOUR_UI::instance()->popup_error (_("You cannot create a track with that name as it is reserved for Ardour"));
1344                 name_entry.set_text (_route->name());
1345         } else {
1346                 _route->set_name (x);
1347         }
1348 }
1349
1350 void
1351 RouteTimeAxisView::visual_click ()
1352 {
1353         popup_display_menu (0);
1354 }
1355
1356 void
1357 RouteTimeAxisView::hide_click ()
1358 {
1359         // LAME fix for hide_button refresh fix
1360         hide_button.set_sensitive(false);
1361
1362         _editor.hide_track_in_display (*this);
1363
1364         hide_button.set_sensitive(true);
1365 }
1366
1367 boost::shared_ptr<Region>
1368 RouteTimeAxisView::find_next_region (nframes_t pos, RegionPoint point, int32_t dir)
1369 {
1370         boost::shared_ptr<Diskstream> stream;
1371         boost::shared_ptr<Playlist> playlist;
1372
1373         if ((stream = get_diskstream()) != 0 && (playlist = stream->playlist()) != 0) {
1374                 return playlist->find_next_region (pos, point, dir);
1375         }
1376
1377         return boost::shared_ptr<Region> ();
1378 }
1379
1380 nframes64_t
1381 RouteTimeAxisView::find_next_region_boundary (nframes64_t pos, int32_t dir)
1382 {
1383         boost::shared_ptr<Diskstream> stream;
1384         boost::shared_ptr<Playlist> playlist;
1385
1386         if ((stream = get_diskstream()) != 0 && (playlist = stream->playlist()) != 0) {
1387                 return playlist->find_next_region_boundary (pos, dir);
1388         }
1389
1390         return -1;
1391 }
1392
1393 bool
1394 RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1395 {
1396         boost::shared_ptr<Playlist> what_we_got;
1397         boost::shared_ptr<Diskstream> ds = get_diskstream();
1398         boost::shared_ptr<Playlist> playlist;
1399         bool ret = false;
1400
1401         if (ds == 0) {
1402                 /* route is a bus, not a track */
1403                 return false;
1404         }
1405
1406         playlist = ds->playlist();
1407
1408         TimeSelection time (selection.time);
1409         float speed = ds->speed();
1410         if (speed != 1.0f) {
1411                 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1412                         (*i).start = session_frame_to_track_frame((*i).start, speed);
1413                         (*i).end   = session_frame_to_track_frame((*i).end,   speed);
1414                 }
1415         }
1416
1417         XMLNode &before = playlist->get_state();
1418         switch (op) {
1419         case Cut:
1420                 if ((what_we_got = playlist->cut (time)) != 0) {
1421                         _editor.get_cut_buffer().add (what_we_got);
1422                         _session.add_command( new MementoCommand<Playlist>(*playlist.get(), &before, &playlist->get_state()));
1423                         ret = true;
1424                 }
1425                 break;
1426         case Copy:
1427                 if ((what_we_got = playlist->copy (time)) != 0) {
1428                         _editor.get_cut_buffer().add (what_we_got);
1429                 }
1430                 break;
1431
1432         case Clear:
1433                 if ((what_we_got = playlist->cut (time)) != 0) {
1434                         _session.add_command( new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1435                         what_we_got->release ();
1436                         ret = true;
1437                 }
1438                 break;
1439         }
1440
1441         return ret;
1442 }
1443
1444 bool
1445 RouteTimeAxisView::paste (nframes_t pos, float times, Selection& selection, size_t nth)
1446 {
1447         if (!is_track()) {
1448                 return false;
1449         }
1450
1451         boost::shared_ptr<Playlist> playlist = get_diskstream()->playlist();
1452         PlaylistSelection::iterator p;
1453
1454         for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth) {}
1455
1456         if (p == selection.playlists.end()) {
1457                 return false;
1458         }
1459
1460         if (get_diskstream()->speed() != 1.0f) {
1461                 pos = session_frame_to_track_frame(pos, get_diskstream()->speed() );
1462         }
1463
1464         XMLNode &before = playlist->get_state();
1465         playlist->paste (*p, pos, times);
1466         _session.add_command( new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1467
1468         return true;
1469 }
1470
1471
1472 TimeAxisView::Children
1473 RouteTimeAxisView::get_child_list()
1474 {
1475         TimeAxisView::Children redirect_children;
1476
1477         for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1478                 if (!(*i)->hidden()) {
1479                         redirect_children.push_back(*i);
1480                 }
1481         }
1482         return redirect_children;
1483 }
1484
1485
1486 void
1487 RouteTimeAxisView::build_playlist_menu (Gtk::Menu * menu)
1488 {
1489         using namespace Menu_Helpers;
1490
1491         if (!menu || !is_track()) {
1492                 return;
1493         }
1494
1495         MenuList& playlist_items = menu->items();
1496         menu->set_name ("ArdourContextMenu");
1497         playlist_items.clear();
1498
1499         delete playlist_menu;
1500
1501         playlist_menu = new Menu;
1502         playlist_menu->set_name ("ArdourContextMenu");
1503
1504         vector<boost::shared_ptr<Playlist> > playlists;
1505         boost::shared_ptr<Diskstream> ds = get_diskstream();
1506         RadioMenuItem::Group playlist_group;
1507
1508         _session.playlists->get (playlists);
1509
1510         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
1511
1512                 if ((*i)->get_orig_diskstream_id() == ds->id()) {
1513                         playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name(), sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist),
1514                                                                                                      boost::weak_ptr<Playlist> (*i))));
1515
1516                         if (ds->playlist()->id() == (*i)->id()) {
1517                                 static_cast<RadioMenuItem*>(&playlist_items.back())->set_active();
1518                         }
1519                 } else if (ds->playlist()->id() == (*i)->id()) {
1520                         playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name(), sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist),
1521                                                                                                      boost::weak_ptr<Playlist>(*i))));
1522                         static_cast<RadioMenuItem*>(&playlist_items.back())->set_active();
1523
1524                 }
1525         }
1526
1527         playlist_items.push_back (SeparatorElem());
1528         playlist_items.push_back (MenuElem (_("Rename"), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
1529         playlist_items.push_back (SeparatorElem());
1530
1531         if (!route_group() || !route_group()->is_active()) {
1532                 playlist_items.push_back (MenuElem (_("New"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1533                 playlist_items.push_back (MenuElem (_("New Copy"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1534
1535         } else {
1536                 // Use a label which tells the user what is happening
1537                 playlist_items.push_back (MenuElem (_("New Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
1538                 playlist_items.push_back (MenuElem (_("Copy Take"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
1539
1540         }
1541
1542         playlist_items.push_back (SeparatorElem());
1543         playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
1544         playlist_items.push_back (SeparatorElem());
1545
1546         playlist_items.push_back (MenuElem(_("Select from all ..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
1547 }
1548
1549 void
1550 RouteTimeAxisView::use_playlist (boost::weak_ptr<Playlist> wpl)
1551 {
1552         assert (is_track());
1553
1554         boost::shared_ptr<Playlist> pl (wpl.lock());
1555
1556         if (!pl) {
1557                 return;
1558         }
1559
1560         boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
1561
1562         if (apl) {
1563                 if (get_diskstream()->playlist() == apl) {
1564                         // radio button cotnrols mean this function is called for both the
1565                         // old and new playlist
1566                         return;
1567                 }
1568                 get_diskstream()->use_playlist (apl);
1569
1570
1571                 if (route_group() && route_group()->is_active()) {
1572                         //PBD::stacktrace(cerr, 20);
1573                         std::string group_string = "."+route_group()->name()+".";
1574
1575                         std::string take_name = apl->name();
1576                         std::string::size_type idx = take_name.find(group_string);
1577
1578                         if (idx == std::string::npos)
1579                                 return;
1580
1581                         take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
1582
1583                         boost::shared_ptr<RouteList> rl (route_group()->route_list());
1584
1585                         for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
1586                                 if ( (*i) == this->route()) {
1587                                         continue;
1588                                 }
1589
1590                                 std::string playlist_name = (*i)->name()+group_string+take_name;
1591
1592                                 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
1593                                 if (!track) {
1594                                         std::cerr << "route " << (*i)->name() << " is not a Track" << std::endl;
1595                                         continue;
1596                                 }
1597
1598                                 boost::shared_ptr<Playlist> ipl = session().playlists->by_name(playlist_name);
1599                                 if (!ipl) {
1600                                         // No playlist for this track for this take yet, make it
1601                                         track->diskstream()->use_new_playlist();
1602                                         track->diskstream()->playlist()->set_name(playlist_name);
1603                                 } else {
1604                                         track->diskstream()->use_playlist(ipl);
1605                                 }
1606                         }
1607                 }
1608         }
1609 }
1610
1611 void
1612 RouteTimeAxisView::show_playlist_selector ()
1613 {
1614         _editor.playlist_selector().show_for (this);
1615 }
1616
1617 void
1618 RouteTimeAxisView::map_frozen ()
1619 {
1620         if (!is_track()) {
1621                 return;
1622         }
1623
1624         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::map_frozen)
1625
1626         switch (track()->freeze_state()) {
1627         case Track::Frozen:
1628                 playlist_button.set_sensitive (false);
1629                 rec_enable_button->set_sensitive (false);
1630                 break;
1631         default:
1632                 playlist_button.set_sensitive (true);
1633                 rec_enable_button->set_sensitive (true);
1634                 break;
1635         }
1636 }
1637
1638 void
1639 RouteTimeAxisView::color_handler ()
1640 {
1641         //case cTimeStretchOutline:
1642         if (timestretch_rect) {
1643                 timestretch_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchOutline.get();
1644         }
1645         //case cTimeStretchFill:
1646         if (timestretch_rect) {
1647                 timestretch_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeStretchFill.get();
1648         }
1649
1650         reset_meter();
1651 }
1652
1653 void
1654 RouteTimeAxisView::toggle_automation_track (Evoral::Parameter param)
1655 {
1656         RouteAutomationNode* node = automation_track(param);
1657
1658         if (!node)
1659                 return;
1660
1661         bool showit = node->menu_item->get_active();
1662
1663         if (showit != node->track->marked_for_display()) {
1664                 if (showit) {
1665                         node->track->set_marked_for_display (true);
1666                         node->track->canvas_display()->show();
1667                         node->track->get_state_node()->add_property ("shown", X_("yes"));
1668                 } else {
1669                         node->track->set_marked_for_display (false);
1670                         node->track->hide ();
1671                         node->track->get_state_node()->add_property ("shown", X_("no"));
1672                 }
1673
1674                 /* now trigger a redisplay */
1675
1676                 if (!no_redraw) {
1677                          _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
1678                 }
1679         }
1680 }
1681
1682 void
1683 RouteTimeAxisView::automation_track_hidden (Evoral::Parameter param)
1684 {
1685         RouteAutomationNode* ran = automation_track(param);
1686         if (!ran) {
1687                 return;
1688         }
1689
1690         // if Evoral::Parameter::operator< doesn't obey strict weak ordering, we may crash here....
1691         _show_automation.erase(param);
1692         ran->track->get_state_node()->add_property (X_("shown"), X_("no"));
1693
1694         if (ran->menu_item && !_hidden) {
1695                 ran->menu_item->set_active (false);
1696         }
1697
1698          _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
1699 }
1700
1701
1702 void
1703 RouteTimeAxisView::show_all_automation ()
1704 {
1705         no_redraw = true;
1706
1707         /* Show our automation */
1708
1709         map<Evoral::Parameter, RouteAutomationNode*>::iterator i;
1710         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1711                 i->second->track->set_marked_for_display (true);
1712                 i->second->track->canvas_display()->show();
1713                 i->second->track->get_state_node()->add_property ("shown", X_("yes"));
1714                 i->second->menu_item->set_active(true);
1715         }
1716
1717
1718         /* Show processor automation */
1719
1720         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1721                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1722                         if ((*ii)->view == 0) {
1723                                 add_processor_automation_curve ((*i)->processor, (*ii)->what);
1724                         }
1725
1726                         (*ii)->menu_item->set_active (true);
1727                 }
1728         }
1729
1730         no_redraw = false;
1731
1732         /* Redraw */
1733
1734          _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
1735 }
1736
1737 void
1738 RouteTimeAxisView::show_existing_automation ()
1739 {
1740         no_redraw = true;
1741
1742         /* Show our automation */
1743
1744         map<Evoral::Parameter, RouteAutomationNode*>::iterator i;
1745         for (i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1746                 if (i->second->track->line() && i->second->track->line()->npoints() > 0) {
1747                         i->second->track->set_marked_for_display (true);
1748                         i->second->track->canvas_display()->show();
1749                         i->second->track->get_state_node()->add_property ("shown", X_("yes"));
1750                         i->second->menu_item->set_active(true);
1751                 }
1752         }
1753
1754
1755         /* Show processor automation */
1756
1757         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1758                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1759                         if ((*ii)->view != 0 && (*i)->processor->data().control((*ii)->what)->list()->size() > 0) {
1760                                 (*ii)->menu_item->set_active (true);
1761                         }
1762                 }
1763         }
1764
1765         no_redraw = false;
1766
1767         _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
1768 }
1769
1770 void
1771 RouteTimeAxisView::hide_all_automation ()
1772 {
1773         no_redraw = true;
1774
1775         /* Hide our automation */
1776
1777         for (map<Evoral::Parameter, RouteAutomationNode*>::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
1778                 i->second->track->set_marked_for_display (false);
1779                 i->second->track->hide ();
1780                 i->second->track->get_state_node()->add_property ("shown", X_("no"));
1781                 i->second->menu_item->set_active (false);
1782         }
1783
1784         /* Hide processor automation */
1785
1786         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1787                 for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1788                         (*ii)->menu_item->set_active (false);
1789                 }
1790         }
1791
1792         _show_automation.clear();
1793
1794         no_redraw = false;
1795          _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
1796 }
1797
1798
1799 void
1800 RouteTimeAxisView::region_view_added (RegionView* rv)
1801 {
1802         /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
1803         if(is_audio_track()) {
1804                 for (Children::iterator i = children.begin(); i != children.end(); ++i) {
1805                         boost::shared_ptr<AutomationTimeAxisView> atv;
1806
1807                         if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
1808                                 atv->add_ghost(rv);
1809                         }
1810                 }
1811         }
1812
1813         for (UnderlayMirrorList::iterator i = _underlay_mirrors.begin(); i != _underlay_mirrors.end(); ++i) {
1814                 (*i)->add_ghost(rv);
1815         }
1816 }
1817
1818 RouteTimeAxisView::ProcessorAutomationInfo::~ProcessorAutomationInfo ()
1819 {
1820         for (vector<ProcessorAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1821                 delete *i;
1822         }
1823 }
1824
1825
1826 RouteTimeAxisView::ProcessorAutomationNode::~ProcessorAutomationNode ()
1827 {
1828         parent.remove_processor_automation_node (this);
1829 }
1830
1831 void
1832 RouteTimeAxisView::remove_processor_automation_node (ProcessorAutomationNode* pan)
1833 {
1834         if (pan->view) {
1835                 remove_child (pan->view);
1836         }
1837 }
1838
1839 RouteTimeAxisView::ProcessorAutomationNode*
1840 RouteTimeAxisView::find_processor_automation_node (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1841 {
1842         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
1843
1844                 if ((*i)->processor == processor) {
1845
1846                         for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1847                                 if ((*ii)->what == what) {
1848                                         return *ii;
1849                                 }
1850                         }
1851                 }
1852         }
1853
1854         return 0;
1855 }
1856
1857 static string
1858 legalize_for_xml_node (string str)
1859 {
1860         string::size_type pos;
1861         string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:";
1862         string legal;
1863
1864         legal = str;
1865         pos = 0;
1866
1867         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
1868                 legal.replace (pos, 1, "_");
1869                 pos += 1;
1870         }
1871
1872         return legal;
1873 }
1874
1875
1876 void
1877 RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
1878 {
1879         string name;
1880         ProcessorAutomationNode* pan;
1881
1882         if ((pan = find_processor_automation_node (processor, what)) == 0) {
1883                 error << _("programming error: ")
1884                       << string_compose (X_("processor automation curve for %1:%2 not registered with track!"),
1885                                   processor->name(), what)
1886                       << endmsg;
1887                 /*NOTREACHED*/
1888                 return;
1889         }
1890
1891         if (pan->view) {
1892                 return;
1893         }
1894
1895         name = processor->describe_parameter (what);
1896
1897         /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
1898
1899         /* FIXME: ew */
1900
1901         char state_name[256];
1902         snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id());
1903
1904         boost::shared_ptr<AutomationControl> control
1905                         = boost::dynamic_pointer_cast<AutomationControl>(processor->data().control(what, true));
1906
1907         pan->view = boost::shared_ptr<AutomationTimeAxisView>(
1908                         new AutomationTimeAxisView (_session, _route, processor, control,
1909                                 _editor, *this, false, parent_canvas, name, state_name));
1910
1911         pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
1912
1913         if (!pan->view->marked_for_display()) {
1914                 pan->view->hide ();
1915         } else {
1916                 pan->menu_item->set_active (true);
1917         }
1918
1919         add_child (pan->view);
1920
1921         if (_view) {
1922                 _view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
1923         }
1924
1925         processor->mark_automation_visible (what, true);
1926 }
1927
1928 void
1929 RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor> i)
1930 {
1931         if (!_hidden) {
1932                 pan->menu_item->set_active (false);
1933         }
1934
1935         i->mark_automation_visible (pan->what, false);
1936
1937          _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
1938 }
1939
1940 void
1941 RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
1942 {
1943         boost::shared_ptr<Processor> processor (p.lock ());
1944         if (!processor) {
1945                 return;
1946         }
1947
1948         set<Evoral::Parameter> s;
1949         boost::shared_ptr<AutomationLine> al;
1950
1951         processor->what_has_visible_data (s);
1952
1953         for (set<Evoral::Parameter>::iterator i = s.begin(); i != s.end(); ++i) {
1954
1955                 if ((al = find_processor_automation_curve (processor, *i)) != 0) {
1956                         al->queue_reset ();
1957                 } else {
1958                         add_processor_automation_curve (processor, (*i));
1959                 }
1960         }
1961 }
1962
1963 void
1964 RouteTimeAxisView::add_automation_child(Evoral::Parameter param, boost::shared_ptr<AutomationTimeAxisView> track, bool show)
1965 {
1966         using namespace Menu_Helpers;
1967
1968         XMLProperty* prop;
1969         XMLNode* node;
1970
1971         add_child (track);
1972
1973         track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
1974
1975         bool hideit = (!show);
1976
1977         if ((node = track->get_state_node()) != 0) {
1978                 if  ((prop = node->property ("shown")) != 0) {
1979                         if (string_is_affirmative (prop->value())) {
1980                                 hideit = false;
1981                         }
1982                 }
1983         }
1984
1985         _automation_tracks.insert(std::make_pair(param, new RouteAutomationNode(param, NULL, track)));
1986
1987         if (hideit) {
1988                 track->hide ();
1989         } else {
1990                 _show_automation.insert (param);
1991
1992
1993                 if (!no_redraw) {
1994                         _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
1995                 }
1996         }
1997
1998         build_display_menu();
1999 }
2000
2001
2002 void
2003 RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p)
2004 {
2005         boost::shared_ptr<Processor> processor (p.lock ());
2006
2007         if (!processor || !processor->display_to_user ()) {
2008                 return;
2009         }
2010
2011         using namespace Menu_Helpers;
2012         ProcessorAutomationInfo *rai;
2013         list<ProcessorAutomationInfo*>::iterator x;
2014
2015         const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
2016         std::set<Evoral::Parameter> has_visible_automation;
2017
2018         processor->what_has_visible_data(has_visible_automation);
2019
2020         if (automatable.empty()) {
2021                 return;
2022         }
2023
2024         for (x = processor_automation.begin(); x != processor_automation.end(); ++x) {
2025                 if ((*x)->processor == processor) {
2026                         break;
2027                 }
2028         }
2029
2030         if (x == processor_automation.end()) {
2031
2032                 rai = new ProcessorAutomationInfo (processor);
2033                 processor_automation.push_back (rai);
2034
2035         } else {
2036
2037                 rai = *x;
2038
2039         }
2040
2041         /* any older menu was deleted at the top of processors_changed()
2042            when we cleared the subplugin menu.
2043         */
2044
2045         rai->menu = manage (new Menu);
2046         MenuList& items = rai->menu->items();
2047         rai->menu->set_name ("ArdourContextMenu");
2048
2049         items.clear ();
2050
2051         for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
2052
2053                 ProcessorAutomationNode* pan;
2054                 CheckMenuItem* mitem;
2055
2056                 string name = processor->describe_parameter (*i);
2057
2058                 items.push_back (CheckMenuElem (name));
2059                 mitem = dynamic_cast<CheckMenuItem*> (&items.back());
2060
2061                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
2062                         mitem->set_active(true);
2063                 }
2064
2065                 if ((pan = find_processor_automation_node (processor, *i)) == 0) {
2066
2067                         /* new item */
2068
2069                         pan = new ProcessorAutomationNode (*i, mitem, *this);
2070
2071                         rai->lines.push_back (pan);
2072
2073                 } else {
2074
2075                         pan->menu_item = mitem;
2076
2077                 }
2078
2079                 mitem->signal_toggled().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_menu_item_toggled), rai, pan));
2080         }
2081
2082         /* add the menu for this processor, because the subplugin
2083            menu is always cleared at the top of processors_changed().
2084            this is the result of some poor design in gtkmm and/or
2085            GTK+.
2086         */
2087
2088         subplugin_menu.items().push_back (MenuElem (processor->name(), *rai->menu));
2089         rai->valid = true;
2090 }
2091
2092 void
2093 RouteTimeAxisView::processor_menu_item_toggled (RouteTimeAxisView::ProcessorAutomationInfo* rai,
2094                                                RouteTimeAxisView::ProcessorAutomationNode* pan)
2095 {
2096         bool showit = pan->menu_item->get_active();
2097         bool redraw = false;
2098
2099         if (pan->view == 0 && showit) {
2100                 add_processor_automation_curve (rai->processor, pan->what);
2101                 redraw = true;
2102         }
2103
2104         if (pan->view && showit != pan->view->marked_for_display()) {
2105
2106                 if (showit) {
2107                         pan->view->set_marked_for_display (true);
2108                         pan->view->canvas_display()->show();
2109                         pan->view->canvas_background()->show();
2110                 } else {
2111                         rai->processor->mark_automation_visible (pan->what, true);
2112                         pan->view->set_marked_for_display (false);
2113                         pan->view->hide ();
2114                 }
2115
2116                 redraw = true;
2117
2118         }
2119
2120         if (redraw && !no_redraw) {
2121
2122                 /* now trigger a redisplay */
2123
2124                  _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
2125
2126         }
2127 }
2128
2129 void
2130 RouteTimeAxisView::processors_changed (RouteProcessorChange c)
2131 {
2132         if (c.type == RouteProcessorChange::MeterPointChange) {
2133                 /* nothing to do if only the meter point has changed */
2134                 return;
2135         }
2136
2137         using namespace Menu_Helpers;
2138
2139         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
2140                 (*i)->valid = false;
2141         }
2142
2143         subplugin_menu.items().clear ();
2144
2145         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
2146         _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
2147
2148         bool deleted_processor_automation = false;
2149
2150         for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ) {
2151
2152                 list<ProcessorAutomationInfo*>::iterator tmp;
2153
2154                 tmp = i;
2155                 ++tmp;
2156
2157                 if (!(*i)->valid) {
2158
2159                         delete *i;
2160                         processor_automation.erase (i);
2161                         deleted_processor_automation = true;
2162
2163                 }
2164
2165                 i = tmp;
2166         }
2167
2168         if (deleted_processor_automation) {
2169                 _route->gui_changed ("visible_tracks", this);
2170         }
2171 }
2172
2173 boost::shared_ptr<AutomationLine>
2174 RouteTimeAxisView::find_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
2175 {
2176         ProcessorAutomationNode* pan;
2177
2178         if ((pan = find_processor_automation_node (processor, what)) != 0) {
2179                 if (pan->view) {
2180                         pan->view->line();
2181                 }
2182         }
2183
2184         return boost::shared_ptr<AutomationLine>();
2185 }
2186
2187 void
2188 RouteTimeAxisView::reset_processor_automation_curves ()
2189 {
2190         for (ProcessorAutomationCurves::iterator i = processor_automation_curves.begin(); i != processor_automation_curves.end(); ++i) {
2191                 (*i)->reset();
2192         }
2193 }
2194
2195 void
2196 RouteTimeAxisView::update_rec_display ()
2197 {
2198         RouteUI::update_rec_display ();
2199         name_entry.set_sensitive (!_route->record_enabled());
2200 }
2201
2202 void
2203 RouteTimeAxisView::set_layer_display (LayerDisplay d)
2204 {
2205         if (_view) {
2206                 _view->set_layer_display (d);
2207         }
2208
2209         ensure_xml_node ();
2210         xml_node->add_property (N_("layer-display"), enum_2_string (d));
2211 }
2212
2213 LayerDisplay
2214 RouteTimeAxisView::layer_display () const
2215 {
2216         if (_view) {
2217                 return _view->layer_display ();
2218         }
2219
2220         /* we don't know, since we don't have a _view, so just return something */
2221         return Overlaid;
2222 }
2223
2224
2225
2226 boost::shared_ptr<AutomationTimeAxisView>
2227 RouteTimeAxisView::automation_child(Evoral::Parameter param)
2228 {
2229         AutomationTracks::iterator i = _automation_tracks.find(param);
2230         if (i != _automation_tracks.end())
2231                 return i->second->track;
2232         else
2233                 return boost::shared_ptr<AutomationTimeAxisView>();
2234 }
2235
2236 void
2237 RouteTimeAxisView::fast_update ()
2238 {
2239         gm.get_level_meter().update_meters ();
2240 }
2241
2242 void
2243 RouteTimeAxisView::hide_meter ()
2244 {
2245         clear_meter ();
2246         gm.get_level_meter().hide_meters ();
2247 }
2248
2249 void
2250 RouteTimeAxisView::show_meter ()
2251 {
2252         reset_meter ();
2253 }
2254
2255 void
2256 RouteTimeAxisView::reset_meter ()
2257 {
2258         if (Config->get_show_track_meters()) {
2259                 gm.get_level_meter().setup_meters (height-5);
2260         } else {
2261                 hide_meter ();
2262         }
2263 }
2264
2265 void
2266 RouteTimeAxisView::clear_meter ()
2267 {
2268         gm.get_level_meter().clear_meters ();
2269 }
2270
2271 void
2272 RouteTimeAxisView::meter_changed (void *src)
2273 {
2274         ENSURE_GUI_THREAD (*this, &RouteTimeAxisView::meter_changed, src)
2275         reset_meter();
2276 }
2277
2278 void
2279 RouteTimeAxisView::io_changed (IOChange /*change*/, void */*src*/)
2280 {
2281         reset_meter ();
2282 }
2283
2284 void
2285 RouteTimeAxisView::build_underlay_menu(Gtk::Menu* parent_menu) {
2286         using namespace Menu_Helpers;
2287
2288         if(!_underlay_streams.empty()) {
2289                 MenuList& parent_items = parent_menu->items();
2290                 Menu* gs_menu = manage (new Menu);
2291                 gs_menu->set_name ("ArdourContextMenu");
2292                 MenuList& gs_items = gs_menu->items();
2293
2294                 parent_items.push_back (MenuElem (_("Underlays"), *gs_menu));
2295
2296                 for(UnderlayList::iterator it = _underlay_streams.begin(); it != _underlay_streams.end(); ++it) {
2297                         gs_items.push_back(MenuElem(string_compose(_("Remove \"%1\""), (*it)->trackview().name()),
2298                                                     sigc::bind(sigc::mem_fun(*this, &RouteTimeAxisView::remove_underlay), *it)));
2299                 }
2300         }
2301 }
2302
2303 bool
2304 RouteTimeAxisView::set_underlay_state()
2305 {
2306         if(!underlay_xml_node) {
2307                 return false;
2308         }
2309
2310         XMLNodeList nlist = underlay_xml_node->children();
2311         XMLNodeConstIterator niter;
2312         XMLNode *child_node;
2313
2314         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2315                 child_node = *niter;
2316
2317                 if(child_node->name() != "Underlay") {
2318                         continue;
2319                 }
2320
2321                 XMLProperty* prop = child_node->property ("id");
2322                 if (prop) {
2323                         PBD::ID id (prop->value());
2324
2325                         RouteTimeAxisView* v = _editor.get_route_view_by_id (id);
2326
2327                         if (v) {
2328                                 add_underlay(v->view(), false);
2329                         }
2330                 }
2331         }
2332
2333         return false;
2334 }
2335
2336 void
2337 RouteTimeAxisView::add_underlay(StreamView* v, bool update_xml)
2338 {
2339         if(!v) {
2340                 return;
2341         }
2342
2343         RouteTimeAxisView& other = v->trackview();
2344
2345         if(find(_underlay_streams.begin(), _underlay_streams.end(), v) == _underlay_streams.end()) {
2346                 if(find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this) != other._underlay_mirrors.end()) {
2347                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2348                         /*NOTREACHED*/
2349                 }
2350
2351                 _underlay_streams.push_back(v);
2352                 other._underlay_mirrors.push_back(this);
2353
2354                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
2355
2356                 if(update_xml) {
2357                         if(!underlay_xml_node) {
2358                                 ensure_xml_node();
2359                                 underlay_xml_node = xml_node->add_child("Underlays");
2360                         }
2361
2362                         XMLNode* node = underlay_xml_node->add_child("Underlay");
2363                         XMLProperty* prop = node->add_property("id");
2364                         prop->set_value(v->trackview().route()->id().to_s());
2365                 }
2366         }
2367 }
2368
2369 void
2370 RouteTimeAxisView::remove_underlay(StreamView* v)
2371 {
2372         if(!v) {
2373                 return;
2374         }
2375
2376         UnderlayList::iterator it = find(_underlay_streams.begin(), _underlay_streams.end(), v);
2377         RouteTimeAxisView& other = v->trackview();
2378
2379         if(it != _underlay_streams.end()) {
2380                 UnderlayMirrorList::iterator gm = find(other._underlay_mirrors.begin(), other._underlay_mirrors.end(), this);
2381
2382                 if(gm == other._underlay_mirrors.end()) {
2383                         fatal << _("programming error: underlay reference pointer pairs are inconsistent!") << endmsg;
2384                         /*NOTREACHED*/
2385                 }
2386
2387                 v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::remove_ghost));
2388
2389                 _underlay_streams.erase(it);
2390                 other._underlay_mirrors.erase(gm);
2391
2392                 if(underlay_xml_node) {
2393                         underlay_xml_node->remove_nodes_and_delete("id", v->trackview().route()->id().to_s());
2394                 }
2395         }
2396 }
2397
2398 void
2399 RouteTimeAxisView::set_button_names ()
2400 {
2401         rec_enable_button_label.set_text (_("r"));
2402
2403         if (Config->get_solo_control_is_listen_control()) {
2404                 switch (Config->get_listen_position()) {
2405                 case AfterFaderListen:
2406                         solo_button_label.set_text (_("A"));
2407                         break;
2408                 case PreFaderListen:
2409                         solo_button_label.set_text (_("P"));
2410                         break;
2411                 }
2412         } else {
2413                 solo_button_label.set_text (_("s"));
2414         }
2415
2416         mute_button_label.set_text (_("m"));
2417 }