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