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