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