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