editor window layout changes, and lots more
[ardour.git] / gtk2_ardour / audio_time_axis.cc
1 /*
2     Copyright (C) 2000 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     $Id$
19 */
20
21 #include <cstdlib>
22 #include <cmath>
23
24 #include <algorithm>
25 #include <string>
26 #include <vector>
27
28 #include <sigc++/bind.h>
29
30 #include <pbd/error.h>
31 #include <pbd/stl_delete.h>
32
33 #include <gtkmm2ext/utils.h>
34 #include <gtkmm2ext/selector.h>
35 #include <gtkmm2ext/gtk_ui.h>
36 #include <gtkmm2ext/stop_signal.h>
37 #include <gtkmm2ext/bindable_button.h>
38
39 #include <ardour/session.h>
40 #include <ardour/session_playlist.h>
41 #include <ardour/audioplaylist.h>
42 #include <ardour/diskstream.h>
43 #include <ardour/utils.h>
44 #include <ardour/playlist.h>
45 #include <ardour/ladspa_plugin.h>
46 #include <ardour/insert.h>
47 #include <ardour/location.h>
48 #include <ardour/panner.h>
49
50 #include "ardour_ui.h"
51 #include "public_editor.h"
52 #include "audio_time_axis.h"
53 #include "streamview.h"
54 #include "simplerect.h"
55 #include "playlist_selector.h"
56 #include "plugin_selector.h"
57 #include "plugin_ui.h"
58 #include "regionview.h"
59 #include "automation_gain_line.h"
60 #include "automation_pan_line.h"
61 #include "automation_time_axis.h"
62 #include "redirect_automation_time_axis.h"
63 #include "gain_automation_time_axis.h"
64 #include "pan_automation_time_axis.h"
65 #include "redirect_automation_line.h"
66 #include "selection.h"
67 #include "point_selection.h"
68 #include "enums.h"
69 #include "utils.h"
70 #include "keyboard.h"
71 #include "rgb_macros.h"
72 #include "prompter.h"
73 #include "crossfade_view.h"
74 #include "gui_thread.h"
75 #include "canvas_impl.h"
76
77 #include <ardour/audio_track.h>
78
79 #include "i18n.h"
80
81 using namespace ARDOUR;
82 //using namespace sigc;
83 using namespace LADSPA;
84 using namespace Gtk;
85 using namespace Editing;
86
87 static const gchar * small_x_xpm[] = {
88 "11 11 2 1",
89 "       c None",
90 ".      c #000000",
91 "           ",
92 "           ",
93 "  .     .  ",
94 "   .   .   ",
95 "    . .    ",
96 "     .     ",
97 "    . .    ",
98 "   .   .   ",
99 "  .     .  ",
100 "           ",
101 "           "};
102
103 AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, Route& rt, Canvas& canvas)
104         : AxisView(sess),
105           RouteUI(rt, sess, _("m"), _("s"), _("r")), // mute, solo, and record
106           TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas),
107           parent_canvas (canvas),
108           button_table (3, 3),
109           edit_group_button (_("g")), // group
110           playlist_button (_("p")), 
111           size_button (_("h")), // height
112           automation_button (_("a")),
113           visual_button (_("v"))
114
115 {
116         _has_state = true;
117         subplugin_menu.set_name ("ArdourContextMenu");
118         playlist_menu = 0;
119         playlist_action_menu = 0;
120         automation_action_menu = 0;
121         gain_track = 0;
122         pan_track = 0;
123         view = 0;
124         timestretch_rect = 0;
125         waveform_item = 0;
126         pan_automation_item = 0;
127         gain_automation_item = 0;
128         no_redraw = false;
129
130         view = new StreamView (*this);
131
132         add_gain_automation_child ();
133         add_pan_automation_child ();
134
135         ignore_toggle = false;
136
137         rec_enable_button->set_active (false);
138         mute_button->set_active (false);
139         solo_button->set_active (false);
140         
141         rec_enable_button->set_name ("TrackRecordEnableButton");
142         mute_button->set_name ("TrackMuteButton");
143         solo_button->set_name ("SoloButton");
144         edit_group_button.set_name ("TrackGroupButton");
145         playlist_button.set_name ("TrackPlaylistButton");
146         automation_button.set_name ("TrackAutomationButton");
147         size_button.set_name ("TrackSizeButton");
148         visual_button.set_name ("TrackVisualButton");
149         hide_button.set_name ("TrackRemoveButton");
150
151         hide_button.add (*(manage (new Image (Gdk::Pixbuf::create_from_xpm_data(small_x_xpm)))));
152         
153         _route.mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
154         _route.solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
155         _route.solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
156
157         _route.panner().Changed.connect (mem_fun(*this, &AudioTimeAxisView::update_pans));
158
159         solo_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::solo_press));
160         solo_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::solo_release));
161         mute_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::mute_press));
162         mute_button->signal_button_release_event().connect (mem_fun(*this, &RouteUI::mute_release));
163         rec_enable_button->signal_button_press_event().connect (mem_fun(*this, &RouteUI::rec_enable_press));
164         edit_group_button.signal_button_release_event().connect (mem_fun(*this, &AudioTimeAxisView::edit_click));
165         playlist_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::playlist_click));
166         automation_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::automation_click));
167         size_button.signal_button_release_event().connect (mem_fun(*this, &AudioTimeAxisView::size_click));
168         visual_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::visual_click));
169         hide_button.signal_clicked().connect (mem_fun(*this, &AudioTimeAxisView::hide_click));
170
171         if (is_audio_track()) {
172                 controls_table.attach (*rec_enable_button, 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
173         }
174         controls_table.attach (*mute_button, 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
175         controls_table.attach (*solo_button, 8, 9, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::FILL|Gtk::EXPAND, 0, 0);
176
177         controls_table.attach (edit_group_button, 7, 8, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
178
179         ARDOUR_UI::instance()->tooltips().set_tip(*rec_enable_button, _("Record"));
180         ARDOUR_UI::instance()->tooltips().set_tip(*solo_button,_("Solo"));
181         ARDOUR_UI::instance()->tooltips().set_tip(*mute_button,_("Mute"));
182         ARDOUR_UI::instance()->tooltips().set_tip(edit_group_button,_("Edit Group"));
183         ARDOUR_UI::instance()->tooltips().set_tip(size_button,_("Display Height"));
184         ARDOUR_UI::instance()->tooltips().set_tip(playlist_button,_("Playlist"));
185         ARDOUR_UI::instance()->tooltips().set_tip(automation_button, _("Automation"));
186         ARDOUR_UI::instance()->tooltips().set_tip(visual_button, _("Visual options"));
187         ARDOUR_UI::instance()->tooltips().set_tip(hide_button, _("Hide this track"));
188         
189         label_view ();
190
191         controls_table.attach (hide_button, 0, 1, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
192         controls_table.attach (visual_button, 1, 2, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
193         controls_table.attach (size_button, 2, 3, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
194         controls_table.attach (automation_button, 3, 4, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
195
196         if (is_audio_track()) {
197                 controls_table.attach (playlist_button, 6, 7, 1, 2, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
198
199         }
200
201         /* remove focus from the buttons */
202         
203         automation_button.unset_flags (Gtk::CAN_FOCUS);
204         solo_button->unset_flags (Gtk::CAN_FOCUS);
205         mute_button->unset_flags (Gtk::CAN_FOCUS);
206         edit_group_button.unset_flags (Gtk::CAN_FOCUS);
207         size_button.unset_flags (Gtk::CAN_FOCUS);
208         playlist_button.unset_flags (Gtk::CAN_FOCUS);
209         hide_button.unset_flags (Gtk::CAN_FOCUS);
210         visual_button.unset_flags (Gtk::CAN_FOCUS);
211
212         /* map current state of the route */
213
214         update_diskstream_display ();
215         solo_changed(0);
216         mute_changed(0);
217         redirects_changed (0);
218         reset_redirect_automation_curves ();
219         y_position = -1;
220
221         ensure_xml_node ();
222
223         set_state (*xml_node);
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.redirects_changed.connect (mem_fun(*this, &AudioTimeAxisView::redirects_changed));
228
229         _route.name_changed.connect (mem_fun(*this, &AudioTimeAxisView::route_name_changed));
230
231         if (is_audio_track()) {
232
233                 /* track */
234
235                 audio_track()->FreezeChange.connect (mem_fun(*this, &AudioTimeAxisView::map_frozen));
236
237                 audio_track()->diskstream_changed.connect (mem_fun(*this, &AudioTimeAxisView::diskstream_changed));
238                 get_diskstream()->speed_changed.connect (mem_fun(*this, &AudioTimeAxisView::speed_changed));
239
240                 controls_ebox.set_name ("AudioTrackControlsBaseUnselected");
241                 controls_base_selected_name = "AudioTrackControlsBaseSelected";
242                 controls_base_unselected_name = "AudioTrackControlsBaseUnselected";
243
244                 /* ask for notifications of any new RegionViews */
245
246                 view->AudioRegionViewAdded.connect (mem_fun(*this, &AudioTimeAxisView::region_view_added));
247
248                 view->attach ();
249
250                 /* pick up the correct freeze state */
251
252                 map_frozen ();
253
254         } else {
255
256                 /* bus */
257
258                 controls_ebox.set_name ("BusControlsBaseUnselected");
259                 controls_base_selected_name = "BusControlsBaseSelected";
260                 controls_base_unselected_name = "BusControlsBaseUnselected";
261         }
262
263         editor.ZoomChanged.connect (mem_fun(*this, &AudioTimeAxisView::reset_samples_per_unit));
264 }
265
266 AudioTimeAxisView::~AudioTimeAxisView ()
267 {
268         GoingAway (); /* EMIT_SIGNAL */
269
270         if (playlist_menu) {
271                 delete playlist_menu;
272                 playlist_menu = 0;
273         }
274   
275         if (playlist_action_menu) {
276                 delete playlist_action_menu;
277                 playlist_action_menu = 0;
278         }
279
280         vector_delete (&redirect_automation_curves);
281
282         for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
283                 delete *i;
284         }
285
286         if (view) {
287                 delete view;
288                 view = 0;
289         }
290 }
291
292 guint32
293 AudioTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
294 {
295         ensure_xml_node ();
296         xml_node->add_property ("shown_editor", "yes");
297                 
298         return TimeAxisView::show_at (y, nth, parent);
299 }
300
301 void
302 AudioTimeAxisView::hide ()
303 {
304         ensure_xml_node ();
305         xml_node->add_property ("shown_editor", "no");
306
307         TimeAxisView::hide ();
308 }
309
310 void
311 AudioTimeAxisView::set_playlist (AudioPlaylist *newplaylist)
312 {
313         AudioPlaylist *pl;
314
315         modified_connection.disconnect ();
316         state_changed_connection.disconnect ();
317         
318         if ((pl = dynamic_cast<AudioPlaylist*> (playlist())) != 0) {
319                 state_changed_connection = pl->StateChanged.connect (mem_fun(*this, &AudioTimeAxisView::playlist_state_changed));
320                 modified_connection = pl->Modified.connect (mem_fun(*this, &AudioTimeAxisView::playlist_modified));
321         }
322 }
323
324 void
325 AudioTimeAxisView::playlist_modified ()
326 {
327 }
328
329 gint
330 AudioTimeAxisView::edit_click (GdkEventButton *ev)
331 {
332         if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
333                 _route.set_edit_group (0, this);
334                 return FALSE;
335         } 
336
337         using namespace Menu_Helpers;
338
339         MenuList& items = edit_group_menu.items ();
340
341         items.clear ();
342         items.push_back (RadioMenuElem (edit_group_menu_radio_group, _("No group"), 
343                                    bind (mem_fun(*this, &AudioTimeAxisView::set_edit_group_from_menu), (RouteGroup *) 0)));
344         
345         if (_route.edit_group() == 0) {
346                 static_cast<RadioMenuItem*>(&items.back())->set_active ();
347         }
348
349         _session.foreach_edit_group (this, &AudioTimeAxisView::add_edit_group_menu_item);
350         edit_group_menu.popup (ev->button, ev->time);
351
352         return FALSE;
353 }
354
355 void
356 AudioTimeAxisView::add_edit_group_menu_item (RouteGroup *eg)
357 {
358         using namespace Menu_Helpers;
359
360         MenuList &items = edit_group_menu.items();
361         items.push_back (RadioMenuElem (edit_group_menu_radio_group,
362                                         eg->name(), bind (mem_fun(*this, &AudioTimeAxisView::set_edit_group_from_menu), eg)));
363         if (_route.edit_group() == eg) {
364                 static_cast<RadioMenuItem*>(&items.back())->set_active ();
365         }
366 }
367
368 void
369 AudioTimeAxisView::set_edit_group_from_menu (RouteGroup *eg)
370
371 {
372         _route.set_edit_group (eg, this);
373 }
374
375 void
376 AudioTimeAxisView::playlist_state_changed (Change ignored)
377 {
378         // ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioTimeAxisView::playlist_state_changed), ignored));
379         // why are we here ?
380 }
381
382 void
383 AudioTimeAxisView::playlist_changed ()
384
385 {
386         label_view ();
387
388         if (is_audio_track()) {
389                 set_playlist (get_diskstream()->playlist());
390         }
391 }
392
393 void
394 AudioTimeAxisView::label_view ()
395 {
396         string x = _route.name();
397
398         if (x != name_entry.get_text()) {
399                 name_entry.set_text (x);
400         }
401
402         ARDOUR_UI::instance()->tooltips().set_tip (name_entry, x);
403 }
404
405 void
406 AudioTimeAxisView::route_name_changed (void *src)
407 {
408         editor.route_name_changed (this);
409         label_view ();
410 }
411
412 void
413 AudioTimeAxisView::take_name_changed (void *src)
414
415 {
416         if (src != this) {
417                 label_view ();
418         }
419 }
420
421 void
422 AudioTimeAxisView::playlist_click ()
423 {
424         // always build a new action menu
425         
426         if (playlist_action_menu == 0) {
427                 playlist_action_menu = new Menu;
428                 playlist_action_menu->set_name ("ArdourContextMenu");
429         }
430         
431         build_playlist_menu(playlist_action_menu);
432
433         playlist_action_menu->popup (1, 0);
434 }
435
436 void
437 AudioTimeAxisView::automation_click ()
438 {
439         if (automation_action_menu == 0) {
440                 /* this seems odd, but the automation action
441                    menu is built as part of the display menu.
442                 */
443                 build_display_menu ();
444         }
445         automation_action_menu->popup (1, 0);
446 }
447
448 void
449 AudioTimeAxisView::show_timestretch (jack_nframes_t start, jack_nframes_t end)
450 {
451         double x1;
452         double x2;
453         double y2;
454         
455         TimeAxisView::show_timestretch (start, end);
456
457         hide_timestretch ();
458
459 #if 0   
460         if (ts.empty()) {
461                 return;
462         }
463
464
465         /* check that the time selection was made in our route, or our edit group.
466            remember that edit_group() == 0 implies the route is *not* in a edit group.
467         */
468
469         if (!(ts.track == this || (ts.group != 0 && ts.group == _route.edit_group()))) {
470                 /* this doesn't apply to us */
471                 return;
472         }
473
474         /* ignore it if our edit group is not active */
475         
476         if ((ts.track != this) && _route.edit_group() && !_route.edit_group()->is_active()) {
477                 return;
478         }
479 #endif
480
481         if (timestretch_rect == 0) {
482                 timestretch_rect = new SimpleRect (*canvas_display);
483                 timestretch_rect->property_x1() =  0.0;
484                 timestretch_rect->property_y1() =  0.0;
485                 timestretch_rect->property_x2() =  0.0;
486                 timestretch_rect->property_y2() =  0.0;
487                 timestretch_rect->property_fill_color_rgba() =  color_map[cTimeStretchFill];
488                 timestretch_rect->property_outline_color_rgba() = color_map[cTimeStretchOutline];
489         }
490
491         timestretch_rect->show ();
492         timestretch_rect->raise_to_top ();
493
494         x1 = start / editor.get_current_zoom();
495         x2 = (end - 1) / editor.get_current_zoom();
496         y2 = height - 2;
497         
498         timestretch_rect->property_x1() = x1;
499         timestretch_rect->property_y1() = 1.0;
500         timestretch_rect->property_x2() = x2;
501         timestretch_rect->property_y2() = y2;
502 }
503
504 void
505 AudioTimeAxisView::hide_timestretch ()
506 {
507         TimeAxisView::hide_timestretch ();
508
509         if (timestretch_rect) {
510                 timestretch_rect->hide ();
511         }
512 }
513
514 void
515 AudioTimeAxisView::show_selection (TimeSelection& ts)
516 {
517
518 #if 0
519         /* ignore it if our edit group is not active or if the selection was started
520            in some other track or edit group (remember that edit_group() == 0 means
521            that the track is not in an edit group).
522         */
523
524         if (((ts.track != this && !is_child (ts.track)) && _route.edit_group() && !_route.edit_group()->is_active()) ||
525             (!(ts.track == this || is_child (ts.track) || (ts.group != 0 && ts.group == _route.edit_group())))) {
526                 hide_selection ();
527                 return;
528         }
529 #endif
530
531         TimeAxisView::show_selection (ts);
532 }
533
534 void
535 AudioTimeAxisView::set_state (const XMLNode& node)
536 {
537         const XMLProperty *prop;
538         
539         TimeAxisView::set_state (node);
540         
541         if ((prop = node.property ("shown_editor")) != 0) {
542                 if (prop->value() == "no") {
543                         _marked_for_display = false;
544                 } else {
545                         _marked_for_display = true;
546                 }
547         } else {
548                 _marked_for_display = true;
549         }
550         
551         XMLNodeList nlist = node.children();
552         XMLNodeConstIterator niter;
553         XMLNode *child_node;
554         
555         
556         show_gain_automation = false;
557         show_pan_automation  = false;
558         
559         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
560                 child_node = *niter;
561
562                 if (child_node->name() == "gain") {
563                         XMLProperty *prop=child_node->property ("shown");
564                         
565                         if (prop != 0) {
566                                 if (prop->value() == "yes") {
567                                         show_gain_automation = true;
568                                 }
569                         }
570                         continue;
571                 }
572                 
573                 if (child_node->name() == "pan") {
574                         XMLProperty *prop=child_node->property ("shown");
575                         
576                         if (prop != 0) {
577                                 if (prop->value() == "yes") {
578                                         show_pan_automation = true;
579                                 }                       
580                         }
581                         continue;
582                 }
583         }
584 }
585
586 void
587 AudioTimeAxisView::set_height (TrackHeight h)
588 {
589         bool height_changed = (h != (TrackHeight)height);
590
591         TimeAxisView::set_height (h);
592
593         ensure_xml_node ();
594
595         view->set_height ((double) height);
596
597         switch (height) {
598         case Largest:
599                 xml_node->add_property ("track_height", "largest");
600                 controls_table.show_all ();
601                 name_label.hide ();
602                 break;
603         case Large:
604                 xml_node->add_property ("track_height", "large");
605                 controls_table.show_all ();
606                 name_label.hide ();
607                 break;
608         case Larger:
609                 xml_node->add_property ("track_height", "larger");
610                 controls_table.show_all ();
611                 name_label.hide ();
612                 break;
613         case Normal:
614                 xml_node->add_property ("track_height", "normal");
615                 controls_table.show_all ();
616                 name_label.hide ();
617                 break;
618         case Smaller:
619                 xml_node->add_property ("track_height", "smaller");
620                 controls_table.show_all ();
621                 name_label.hide ();
622                 edit_group_button.hide ();
623                 hide_button.hide ();
624                 visual_button.hide ();
625                 size_button.hide ();
626                 automation_button.hide ();
627                 playlist_button.hide ();
628                 break;
629         case Small:
630                 xml_node->add_property ("track_height", "small");
631                 controls_table.hide_all ();
632                 controls_table.show ();
633                 name_label.set_text (_route.name());
634                 name_label.show ();
635                 name_hbox.show ();
636                 break;
637         }
638
639         if (height_changed) {
640                 /* only emit the signal if the height really changed */
641                  _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
642         }
643 }
644
645 void
646 AudioTimeAxisView::select_track_color ()
647 {
648         if (RouteUI::choose_color ()) {
649
650                 if (view) {
651                         view->apply_color (_color, StreamView::RegionColor);
652                 }
653         }
654 }
655
656 void
657 AudioTimeAxisView::reset_redirect_automation_curves ()
658 {
659         for (vector<RedirectAutomationLine*>::iterator i = redirect_automation_curves.begin(); i != redirect_automation_curves.end(); ++i) {
660                 (*i)->reset();
661         }
662 }
663
664 void
665 AudioTimeAxisView::reset_samples_per_unit ()
666 {
667         set_samples_per_unit (editor.get_current_zoom());
668 }
669
670 void
671 AudioTimeAxisView::set_samples_per_unit (double spu)
672 {
673         double speed = 1.0;
674
675         if (get_diskstream() != 0) {
676                 speed = get_diskstream()->speed();
677         }
678         
679         if (view) {
680                 view->set_samples_per_unit (spu * speed);
681         }
682
683         TimeAxisView::set_samples_per_unit (spu * speed);
684 }
685
686 void
687 AudioTimeAxisView::build_display_menu ()
688 {
689         using namespace Menu_Helpers;
690
691         /* get the size menu ready */
692
693         build_size_menu ();
694
695         /* prepare it */
696
697         TimeAxisView::build_display_menu ();
698
699         /* now fill it with our stuff */
700
701         MenuList& items = display_menu->items();
702         display_menu->set_name ("ArdourContextMenu");
703         
704         items.push_back (MenuElem (_("Height"), *size_menu));
705         items.push_back (MenuElem (_("Color"), mem_fun(*this, &AudioTimeAxisView::select_track_color)));
706
707
708         items.push_back (SeparatorElem());
709         items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades)));
710         items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades)));
711         items.push_back (SeparatorElem());
712
713
714         automation_action_menu = manage (new Menu);
715         MenuList& automation_items = automation_action_menu->items();
716         automation_action_menu->set_name ("ArdourContextMenu");
717         
718         automation_items.push_back (MenuElem (_("show all automation"),
719                                               mem_fun(*this, &AudioTimeAxisView::show_all_automation)));
720
721         automation_items.push_back (MenuElem (_("show existing automation"),
722                                               mem_fun(*this, &AudioTimeAxisView::show_existing_automation)));
723
724         automation_items.push_back (MenuElem (_("hide all automation"),
725                                               mem_fun(*this, &AudioTimeAxisView::hide_all_automation)));
726
727         automation_items.push_back (SeparatorElem());
728
729         automation_items.push_back (CheckMenuElem (_("gain"), 
730                                                    mem_fun(*this, &AudioTimeAxisView::toggle_gain_track)));
731         gain_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
732         gain_automation_item->set_active(show_gain_automation);
733
734         automation_items.push_back (CheckMenuElem (_("pan"),
735                                                    mem_fun(*this, &AudioTimeAxisView::toggle_pan_track)));
736         pan_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
737         pan_automation_item->set_active(show_pan_automation);
738
739         automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu));
740
741         items.push_back (MenuElem (_("Automation"), *automation_action_menu));
742
743         Menu *waveform_menu = manage(new Menu);
744         MenuList& waveform_items = waveform_menu->items();
745         waveform_menu->set_name ("ArdourContextMenu");
746         
747         waveform_items.push_back (CheckMenuElem (_("Show waveforms"), mem_fun(*this, &AudioTimeAxisView::toggle_waveforms)));
748         waveform_item = static_cast<CheckMenuItem *> (&waveform_items.back());
749         ignore_toggle = true;
750         waveform_item->set_active (editor.show_waveforms());
751         ignore_toggle = false;
752
753         RadioMenuItem::Group group;
754
755         waveform_items.push_back (RadioMenuElem (group, _("Traditional"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Traditional)));
756         traditional_item = static_cast<RadioMenuItem *> (&waveform_items.back());
757
758         waveform_items.push_back (RadioMenuElem (group, _("Rectified"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Rectified)));
759         rectified_item = static_cast<RadioMenuItem *> (&waveform_items.back());
760
761         items.push_back (MenuElem (_("Waveform"), *waveform_menu));
762
763         if (is_audio_track()) {
764
765                 Menu* alignment_menu = manage (new Menu);
766                 MenuList& alignment_items = alignment_menu->items();
767                 alignment_menu->set_name ("ArdourContextMenu");
768
769                 RadioMenuItem::Group align_group;
770                 
771                 alignment_items.push_back (RadioMenuElem (align_group, _("align with existing material"), bind (mem_fun(*this, &AudioTimeAxisView::set_align_style), ExistingMaterial)));
772                 align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
773                 if (get_diskstream()->alignment_style() == ExistingMaterial) {
774                         align_existing_item->set_active();
775                 }
776                 alignment_items.push_back (RadioMenuElem (align_group, _("align with capture time"), bind (mem_fun(*this, &AudioTimeAxisView::set_align_style), CaptureTime)));
777                 align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
778                 if (get_diskstream()->alignment_style() == CaptureTime) {
779                         align_capture_item->set_active();
780                 }
781                 
782                 items.push_back (MenuElem (_("Alignment"), *alignment_menu));
783
784                 get_diskstream()->AlignmentStyleChanged.connect (mem_fun(*this, &AudioTimeAxisView::align_style_changed));
785         }
786
787         items.push_back (SeparatorElem());
788         items.push_back (CheckMenuElem (_("Active"), mem_fun(*this, &RouteUI::toggle_route_active)));
789         route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
790         route_active_menu_item->set_active (_route.active());
791
792         items.push_back (SeparatorElem());
793         items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
794
795 }
796
797 void
798 AudioTimeAxisView::align_style_changed ()
799 {
800         switch (get_diskstream()->alignment_style()) {
801         case ExistingMaterial:
802                 if (!align_existing_item->get_active()) {
803                         align_existing_item->set_active();
804                 }
805                 break;
806         case CaptureTime:
807                 if (!align_capture_item->get_active()) {
808                         align_capture_item->set_active();
809                 }
810                 break;
811         }
812 }
813
814 void
815 AudioTimeAxisView::set_align_style (AlignStyle style)
816 {
817         get_diskstream()->set_align_style (style);
818 }
819
820 void
821 AudioTimeAxisView::rename_current_playlist ()
822 {
823         ArdourPrompter prompter (true);
824         string name;
825
826         AudioPlaylist *pl;
827         DiskStream *ds;
828
829         if (((ds = get_diskstream()) == 0) ||((pl = ds->playlist()) == 0)) {
830                 return;
831         }
832
833         prompter.set_prompt (_("Name for playlist"));
834         prompter.set_initial_text (pl->name());
835
836         switch (prompter.run ()) {
837         case GTK_RESPONSE_ACCEPT:
838                 prompter.get_result (name);
839                 pl->set_name (name);
840                 break;
841
842         default:
843                 break;
844         }
845 }
846
847 void
848 AudioTimeAxisView::playlist_selected (AudioPlaylist *pl)
849 {
850         DiskStream *ds;
851
852         if ((ds = get_diskstream()) != 0) {
853                 ds->use_playlist (pl);
854         }
855 }
856
857 void
858 AudioTimeAxisView::use_copy_playlist ()
859 {
860         AudioPlaylist *pl;
861         DiskStream *ds;
862         string name;
863
864         if (((ds = get_diskstream()) == 0) || ((pl = ds->playlist()) == 0)) {
865                 return;
866         }
867         
868         ArdourPrompter prompter (true);
869         string new_name = Playlist::bump_name (pl->name(), _session);
870         
871         prompter.set_prompt (_("Name for playlist"));
872         prompter.set_initial_text (new_name);
873         prompter.show_all ();
874
875         switch (prompter.run ()) {
876         case GTK_RESPONSE_ACCEPT:
877                 prompter.get_result (name);
878                 ds->use_copy_playlist ();
879                 pl = ds->playlist();
880                 pl->set_name (name);
881                 break;
882
883         default:
884                 break;
885         }
886 }
887
888 void
889 AudioTimeAxisView::use_new_playlist ()
890 {
891         AudioPlaylist *pl;
892         DiskStream *ds;
893         string name;
894
895         if (((ds = get_diskstream()) == 0) || ((pl = ds->playlist()) == 0)) {
896                 return;
897         }
898
899         ArdourPrompter prompter (true);
900         string new_name = Playlist::bump_name (pl->name(), _session);
901
902         prompter.set_prompt (_("Name for playlist"));
903         prompter.set_initial_text (new_name);
904         
905         switch (prompter.run ()) {
906         case GTK_RESPONSE_ACCEPT:
907                 prompter.get_result (name);
908                 ds->use_new_playlist ();
909                 pl = ds->playlist();
910                 pl->set_name (name);
911                 break;
912
913         default:
914                 break;
915         }
916 }       
917
918 void
919 AudioTimeAxisView::clear_playlist ()
920 {
921         AudioPlaylist *pl;
922         DiskStream *ds;
923         
924         if ((ds = get_diskstream()) != 0) {
925                 if ((pl = ds->playlist()) != 0) {
926                         editor.clear_playlist (*pl);
927                 }
928         }
929 }
930
931 void
932 AudioTimeAxisView::toggle_waveforms ()
933 {
934         if (view && waveform_item && !ignore_toggle) {
935                 view->set_show_waveforms (waveform_item->get_active());
936         }
937 }
938
939 void
940 AudioTimeAxisView::set_show_waveforms (bool yn)
941 {
942         if (waveform_item) {
943                 waveform_item->set_active (yn);
944         } else {
945                 view->set_show_waveforms (yn);
946         }
947 }
948
949 void
950 AudioTimeAxisView::set_show_waveforms_recording (bool yn)
951 {
952         if (view) {
953                 view->set_show_waveforms_recording (yn);
954         }
955 }
956
957 void
958 AudioTimeAxisView::set_waveform_shape (WaveformShape shape)
959 {
960         if (view) {
961                 view->set_waveform_shape (shape);
962         }
963 }
964
965 void
966 AudioTimeAxisView::speed_changed ()
967 {
968         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AudioTimeAxisView::reset_samples_per_unit));
969 }
970
971 void
972 AudioTimeAxisView::diskstream_changed (void *src)
973 {
974         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AudioTimeAxisView::update_diskstream_display));
975 }       
976
977 void
978 AudioTimeAxisView::update_diskstream_display ()
979 {
980         DiskStream *ds;
981
982         if ((ds = get_diskstream()) != 0) {
983                 set_playlist (ds->playlist ());
984         }
985
986         map_frozen ();
987 }       
988
989 void
990 AudioTimeAxisView::selection_click (GdkEventButton* ev)
991 {
992         PublicEditor::TrackViewList* tracks = editor.get_valid_views (this, _route.edit_group());
993
994         if (Keyboard::modifier_state_contains (ev->state, Keyboard::Shift)) {
995                 if (editor.get_selection().selected (this)) {
996                         editor.get_selection().remove (*tracks);
997                 } else {
998                         editor.get_selection().add (*tracks);
999                 }
1000         } else {
1001                 editor.get_selection().set (*tracks);
1002         }
1003
1004         delete tracks;
1005 }
1006
1007 void
1008 AudioTimeAxisView::set_selected_regionviews (AudioRegionSelection& regions)
1009 {
1010         if (view) {
1011                 view->set_selected_regionviews (regions);
1012         }
1013 }
1014
1015 void
1016 AudioTimeAxisView::set_selected_points (PointSelection& points)
1017 {
1018         for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
1019                 (*i)->set_selected_points (points);
1020         }
1021 }
1022
1023 void
1024 AudioTimeAxisView::get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable*>& results)
1025 {
1026         double speed = 1.0;
1027         
1028         if (get_diskstream() != 0) {
1029                 speed = get_diskstream()->speed();
1030         }
1031         
1032         jack_nframes_t start_adjusted = session_frame_to_track_frame(start, speed);
1033         jack_nframes_t end_adjusted   = session_frame_to_track_frame(end, speed);
1034
1035         if (view && touched (top, bot)) {
1036                 view->get_selectables (start_adjusted, end_adjusted, results);
1037         }
1038
1039         /* pick up visible automation tracks */
1040         
1041         for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
1042                 if (!(*i)->hidden()) {
1043                         (*i)->get_selectables (start_adjusted, end_adjusted, top, bot, results);
1044                 }
1045         }
1046 }
1047
1048 void
1049 AudioTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
1050 {
1051         if (view) {
1052                 view->get_inverted_selectables (sel, results);
1053         }
1054
1055         for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
1056                 if (!(*i)->hidden()) {
1057                         (*i)->get_inverted_selectables (sel, results);
1058                 }
1059         }
1060
1061         return;
1062 }
1063
1064 RouteGroup*
1065 AudioTimeAxisView::edit_group() const
1066 {
1067         return _route.edit_group();
1068 }
1069
1070 string
1071 AudioTimeAxisView::name() const
1072 {
1073         return _route.name();
1074 }
1075
1076 Playlist *
1077 AudioTimeAxisView::playlist () const 
1078 {
1079         DiskStream *ds;
1080
1081         if ((ds = get_diskstream()) != 0) {
1082                 return ds->playlist(); 
1083         } else {
1084                 return 0; 
1085         }
1086 }
1087
1088 void
1089 AudioTimeAxisView::name_entry_changed ()
1090 {
1091         string x;
1092
1093         x = name_entry.get_text ();
1094         
1095         if (x == _route.name()) {
1096                 return;
1097         }
1098
1099         if (x.length() == 0) {
1100                 name_entry.set_text (_route.name());
1101                 return;
1102         }
1103
1104         strip_whitespace_edges(x);
1105
1106         if (_session.route_name_unique (x)) {
1107                 _route.set_name (x, this);
1108         } else {
1109                 ARDOUR_UI::instance()->popup_error (_("a track already exists with that name"));
1110                 name_entry.set_text (_route.name());
1111         }
1112 }
1113
1114 void
1115 AudioTimeAxisView::visual_click ()
1116 {
1117         popup_display_menu (0);
1118 }
1119
1120 void
1121 AudioTimeAxisView::hide_click ()
1122 {
1123         editor.unselect_strip_in_display (*this);
1124 }
1125
1126 Region*
1127 AudioTimeAxisView::find_next_region (jack_nframes_t pos, RegionPoint point, int32_t dir)
1128 {
1129         DiskStream *stream;
1130         AudioPlaylist *playlist;
1131
1132         if ((stream = get_diskstream()) != 0 && (playlist = stream->playlist()) != 0) {
1133                 return playlist->find_next_region (pos, point, dir);
1134         }
1135
1136         return 0;
1137 }
1138
1139 void
1140 AudioTimeAxisView::add_gain_automation_child ()
1141 {
1142         XMLProperty* prop;
1143         AutomationLine* line;
1144
1145         gain_track = new GainAutomationTimeAxisView (_session,
1146                                                      _route,
1147                                                      editor,
1148                                                      *this,
1149                                                      parent_canvas,
1150                                                      _("gain"),
1151                                                      _route.gain_automation_curve());
1152         
1153         line = new AutomationGainLine ("automation gain",
1154                                        _session,
1155                                        *gain_track,
1156                                        *gain_track->canvas_display,
1157                                        _route.gain_automation_curve());
1158
1159         line->set_line_color (color_map[cAutomationLine]);
1160         
1161
1162         gain_track->add_line (*line);
1163
1164         add_child (gain_track);
1165
1166         gain_track->Hiding.connect (mem_fun(*this, &AudioTimeAxisView::gain_hidden));
1167
1168         bool hideit = true;
1169         
1170         XMLNode* node;
1171
1172         if ((node = gain_track->get_state_node()) != 0) {
1173                 if  ((prop = node->property ("shown")) != 0) {
1174                         if (prop->value() == "yes") {
1175                                 hideit = false;
1176                         }
1177                 } 
1178         }
1179
1180         if (hideit) {
1181                 gain_track->hide ();
1182         }
1183 }
1184
1185 void
1186 AudioTimeAxisView::add_pan_automation_child ()
1187 {
1188         XMLProperty* prop;
1189
1190         pan_track = new PanAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, _("pan"));
1191
1192         update_pans ();
1193         
1194         add_child (pan_track);
1195
1196         pan_track->Hiding.connect (mem_fun(*this, &AudioTimeAxisView::pan_hidden));
1197
1198         ensure_xml_node ();
1199         bool hideit = true;
1200         
1201         XMLNode* node;
1202
1203         if ((node = pan_track->get_state_node()) != 0) {
1204                 if ((prop = node->property ("shown")) != 0) {
1205                         if (prop->value() == "yes") {
1206                                 hideit = false;
1207                         }
1208                 } 
1209         }
1210
1211         if (hideit) {
1212                 pan_track->hide ();
1213         }
1214 }
1215
1216 void
1217 AudioTimeAxisView::update_pans ()
1218 {
1219         Panner::iterator p;
1220         
1221         pan_track->clear_lines ();
1222         
1223         /* we don't draw lines for "greater than stereo" panning.
1224          */
1225
1226         if (_route.n_outputs() > 2) {
1227                 return;
1228         }
1229
1230         for (p = _route.panner().begin(); p != _route.panner().end(); ++p) {
1231
1232                 AutomationLine* line;
1233
1234                 line = new AutomationPanLine ("automation pan", _session, *pan_track,
1235                                               *pan_track->canvas_display, 
1236                                               (*p)->automation());
1237
1238                 if (p == _route.panner().begin()) {
1239                         /* first line is a nice orange */
1240                         line->set_line_color (color_map[cLeftPanAutomationLine]);
1241                 } else {
1242                         /* second line is a nice blue */
1243                         line->set_line_color (color_map[cRightPanAutomationLine]);
1244                 }
1245
1246                 pan_track->add_line (*line);
1247         }
1248 }
1249                 
1250 void
1251 AudioTimeAxisView::toggle_gain_track ()
1252 {
1253
1254         bool showit = gain_automation_item->get_active();
1255
1256         if (showit != gain_track->marked_for_display()) {
1257                 if (showit) {
1258                         gain_track->set_marked_for_display (true);
1259                         gain_track->canvas_display->show();
1260                         gain_track->get_state_node()->add_property ("shown", X_("yes"));
1261                 } else {
1262                         gain_track->set_marked_for_display (false);
1263                         gain_track->hide ();
1264                         gain_track->get_state_node()->add_property ("shown", X_("no"));
1265                 }
1266
1267                 /* now trigger a redisplay */
1268                 
1269                 if (!no_redraw) {
1270                          _route.gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
1271                 }
1272         }
1273 }
1274
1275 void
1276 AudioTimeAxisView::gain_hidden ()
1277 {
1278         gain_track->get_state_node()->add_property (X_("shown"), X_("no"));
1279
1280         if (gain_automation_item && !_hidden) {
1281                 gain_automation_item->set_active (false);
1282         }
1283
1284          _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1285 }
1286
1287 void
1288 AudioTimeAxisView::toggle_pan_track ()
1289 {
1290         bool showit = pan_automation_item->get_active();
1291
1292         if (showit != pan_track->marked_for_display()) {
1293                 if (showit) {
1294                         pan_track->set_marked_for_display (true);
1295                         pan_track->canvas_display->show();
1296                         pan_track->get_state_node()->add_property ("shown", X_("yes"));
1297                 } else {
1298                         pan_track->set_marked_for_display (false);
1299                         pan_track->hide ();
1300                         pan_track->get_state_node()->add_property ("shown", X_("no"));
1301                 }
1302
1303                 /* now trigger a redisplay */
1304                 
1305                 if (!no_redraw) {
1306                          _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1307                 }
1308         }
1309 }
1310
1311 void
1312 AudioTimeAxisView::pan_hidden ()
1313 {
1314         pan_track->get_state_node()->add_property ("shown", "no");
1315
1316         if (pan_automation_item && !_hidden) {
1317                 pan_automation_item->set_active (false);
1318         }
1319
1320          _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1321 }
1322
1323 AudioTimeAxisView::RedirectAutomationInfo::~RedirectAutomationInfo ()
1324 {
1325         for (vector<RedirectAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
1326                 delete *i;
1327         }
1328 }
1329
1330
1331 AudioTimeAxisView::RedirectAutomationNode::~RedirectAutomationNode ()
1332 {
1333         parent.remove_ran (this);
1334
1335         if (view) {
1336                 delete view;
1337         }
1338 }
1339
1340 void
1341 AudioTimeAxisView::remove_ran (RedirectAutomationNode* ran)
1342 {
1343         if (ran->view) {
1344                 remove_child (ran->view);
1345         }
1346 }
1347
1348 AudioTimeAxisView::RedirectAutomationNode*
1349 AudioTimeAxisView::find_redirect_automation_node (Redirect *redirect, uint32_t what)
1350 {
1351         for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
1352
1353                 if ((*i)->redirect == redirect) {
1354
1355                         for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1356                                 if ((*ii)->what == what) {
1357                                         return *ii;
1358                                 }
1359                         }
1360                 }
1361         }
1362
1363         return 0;
1364 }
1365
1366 static string 
1367 legalize_for_xml_node (string str)
1368 {
1369         string::size_type pos;
1370         string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:";
1371         string legal;
1372
1373         legal = str;
1374         pos = 0;
1375
1376         while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
1377                 legal.replace (pos, 1, "_");
1378                 pos += 1;
1379         }
1380
1381         return legal;
1382 }
1383
1384
1385 void
1386 AudioTimeAxisView::add_redirect_automation_curve (Redirect *redirect, uint32_t what)
1387 {
1388         RedirectAutomationLine* ral;
1389         string name;
1390         RedirectAutomationNode* ran;
1391
1392         if ((ran = find_redirect_automation_node (redirect, what)) == 0) {
1393                 fatal << _("programming error: ")
1394                       << string_compose (X_("redirect automation curve for %1:%2 not registered with audio track!"),
1395                                   redirect->name(), what)
1396                       << endmsg;
1397                 /*NOTREACHED*/
1398                 return;
1399         }
1400
1401         if (ran->view) {
1402                 return;
1403         }
1404
1405         name = redirect->describe_parameter (what);
1406
1407         /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
1408
1409         char state_name[256];
1410         snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (redirect->name()).c_str(), what);
1411
1412         ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *redirect, state_name);
1413
1414         ral = new RedirectAutomationLine (name, 
1415                                           *redirect, what, _session, *ran->view,
1416                                           *ran->view->canvas_display, redirect->automation_list (what));
1417         
1418         ral->set_line_color (color_map[cRedirectAutomationLine]);
1419         ral->queue_reset ();
1420
1421         ran->view->add_line (*ral);
1422
1423         ran->view->Hiding.connect (bind (mem_fun(*this, &AudioTimeAxisView::redirect_automation_track_hidden), ran, redirect));
1424
1425         if (!ran->view->marked_for_display()) {
1426                 ran->view->hide ();
1427         } else {
1428                 ran->menu_item->set_active (true);
1429         }
1430
1431         add_child (ran->view);
1432
1433         view->foreach_regionview (bind (mem_fun(*this, &AudioTimeAxisView::add_ghost_to_redirect), ran->view));
1434
1435         redirect->mark_automation_visible (what, true);
1436 }
1437
1438 void
1439 AudioTimeAxisView::redirect_automation_track_hidden (AudioTimeAxisView::RedirectAutomationNode* ran, Redirect* r)
1440 {
1441         if (!_hidden) {
1442                 ran->menu_item->set_active (false);
1443         }
1444
1445         r->mark_automation_visible (ran->what, false);
1446
1447          _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1448 }
1449
1450 void
1451 AudioTimeAxisView::add_existing_redirect_automation_curves (Redirect *redirect)
1452 {
1453         set<uint32_t> s;
1454         RedirectAutomationLine *ral;
1455
1456         redirect->what_has_visible_automation (s);
1457
1458         for (set<uint32_t>::iterator i = s.begin(); i != s.end(); ++i) {
1459                 
1460                 if ((ral = find_redirect_automation_curve (redirect, *i)) != 0) {
1461                         ral->queue_reset ();
1462                 } else {
1463                         add_redirect_automation_curve (redirect, (*i));
1464                 }
1465         }
1466 }
1467
1468 void
1469 AudioTimeAxisView::add_redirect_to_subplugin_menu (Redirect* r)
1470 {
1471         using namespace Menu_Helpers;
1472         RedirectAutomationInfo *rai;
1473         list<RedirectAutomationInfo*>::iterator x;
1474         
1475         const std::set<uint32_t>& automatable = r->what_can_be_automated ();
1476         std::set<uint32_t> has_visible_automation;
1477
1478         r->what_has_visible_automation(has_visible_automation);
1479
1480         if (automatable.empty()) {
1481                 return;
1482         }
1483
1484         for (x = redirect_automation.begin(); x != redirect_automation.end(); ++x) {
1485                 if ((*x)->redirect == r) {
1486                         break;
1487                 }
1488         }
1489
1490         if (x == redirect_automation.end()) {
1491
1492                 rai = new RedirectAutomationInfo (r);
1493                 redirect_automation.push_back (rai);
1494
1495         } else {
1496
1497                 rai = *x;
1498
1499         }
1500
1501         /* any older menu was deleted at the top of redirects_changed()
1502            when we cleared the subplugin menu.
1503         */
1504
1505         rai->menu = manage (new Menu);
1506         MenuList& items = rai->menu->items();
1507         rai->menu->set_name ("ArdourContextMenu");
1508
1509         items.clear ();
1510
1511         for (std::set<uint32_t>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
1512
1513                 RedirectAutomationNode* ran;
1514                 CheckMenuItem* mitem;
1515                 
1516                 string name = r->describe_parameter (*i);
1517                 
1518                 items.push_back (CheckMenuElem (name));
1519                 mitem = dynamic_cast<CheckMenuItem*> (&items.back());
1520
1521                 if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
1522                         mitem->set_active(true);
1523                 }
1524
1525                 if ((ran = find_redirect_automation_node (r, *i)) == 0) {
1526
1527                         /* new item */
1528                         
1529                         ran = new RedirectAutomationNode (*i, mitem, *this);
1530                         
1531                         rai->lines.push_back (ran);
1532
1533                 } else {
1534
1535                         ran->menu_item = mitem;
1536
1537                 }
1538
1539                 mitem->signal_toggled().connect (bind (mem_fun(*this, &AudioTimeAxisView::redirect_menu_item_toggled), rai, ran));
1540         }
1541
1542         /* add the menu for this redirect, because the subplugin
1543            menu is always cleared at the top of redirects_changed().
1544            this is the result of some poor design in gtkmm and/or
1545            GTK+.
1546         */
1547
1548         subplugin_menu.items().push_back (MenuElem (r->name(), *rai->menu));
1549         rai->valid = true;
1550 }
1551
1552 void
1553 AudioTimeAxisView::redirect_menu_item_toggled (AudioTimeAxisView::RedirectAutomationInfo* rai,
1554                                                AudioTimeAxisView::RedirectAutomationNode* ran)
1555 {
1556         bool showit = ran->menu_item->get_active();
1557         bool redraw = false;
1558
1559         if (ran->view == 0 && showit) {
1560                 add_redirect_automation_curve (rai->redirect, ran->what);
1561                 redraw = true;
1562         }
1563
1564         if (showit != ran->view->marked_for_display()) {
1565
1566                 if (showit) {
1567                         ran->view->set_marked_for_display (true);
1568                         ran->view->canvas_display->show();
1569                 } else {
1570                         rai->redirect->mark_automation_visible (ran->what, true);
1571                         ran->view->set_marked_for_display (false);
1572                         ran->view->hide ();
1573                 }
1574
1575                 redraw = true;
1576
1577         }
1578
1579         if (redraw && !no_redraw) {
1580
1581                 /* now trigger a redisplay */
1582                 
1583                  _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1584
1585         }
1586 }
1587
1588 void
1589 AudioTimeAxisView::redirects_changed (void *src)
1590 {
1591         using namespace Menu_Helpers;
1592
1593         for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
1594                 (*i)->valid = false;
1595         }
1596
1597         subplugin_menu.items().clear ();
1598
1599         _route.foreach_redirect (this, &AudioTimeAxisView::add_redirect_to_subplugin_menu);
1600         _route.foreach_redirect (this, &AudioTimeAxisView::add_existing_redirect_automation_curves);
1601
1602         for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ) {
1603
1604                 list<RedirectAutomationInfo*>::iterator tmp;
1605
1606                 tmp = i;
1607                 ++tmp;
1608
1609                 if (!(*i)->valid) {
1610
1611                         delete *i;
1612                         redirect_automation.erase (i);
1613
1614                 } 
1615
1616                 i = tmp;
1617         }
1618
1619         /* change in visibility was possible */
1620
1621         _route.gui_changed ("track_height", this);
1622 }
1623
1624 RedirectAutomationLine *
1625 AudioTimeAxisView::find_redirect_automation_curve (Redirect *redirect, uint32_t what)
1626 {
1627         RedirectAutomationNode* ran;
1628
1629         if ((ran = find_redirect_automation_node (redirect, what)) != 0) {
1630                 if (ran->view) {
1631                         return dynamic_cast<RedirectAutomationLine*> (ran->view->lines.front());
1632                 } 
1633         }
1634
1635         return 0;
1636 }
1637
1638 void
1639 AudioTimeAxisView::show_all_automation ()
1640 {
1641         no_redraw = true;
1642
1643         pan_automation_item->set_active (true);
1644         gain_automation_item->set_active (true);
1645         
1646         for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
1647                 for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1648                         if ((*ii)->view == 0) {
1649                                 add_redirect_automation_curve ((*i)->redirect, (*ii)->what);
1650                         } 
1651
1652                         (*ii)->menu_item->set_active (true);
1653                 }
1654         }
1655
1656         no_redraw = false;
1657
1658          _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1659 }
1660
1661 void
1662 AudioTimeAxisView::show_existing_automation ()
1663 {
1664         no_redraw = true;
1665
1666         pan_automation_item->set_active (true);
1667         gain_automation_item->set_active (true);
1668
1669         for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
1670                 for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1671                         if ((*ii)->view != 0) {
1672                                 (*ii)->menu_item->set_active (true);
1673                         }
1674                 }
1675         }
1676
1677         no_redraw = false;
1678
1679          _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1680 }
1681
1682 void
1683 AudioTimeAxisView::hide_all_automation ()
1684 {
1685         no_redraw = true;
1686
1687         pan_automation_item->set_active (false);
1688         gain_automation_item->set_active (false);
1689
1690         for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
1691                 for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
1692                         (*ii)->menu_item->set_active (false);
1693                 }
1694         }
1695
1696         no_redraw = false;
1697          _route.gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1698 }
1699
1700 bool
1701 AudioTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
1702 {
1703         Playlist* what_we_got;
1704         DiskStream* ds = get_diskstream();
1705         Playlist* playlist;
1706         bool ret = false;
1707
1708         if (ds == 0) {
1709                 /* route is a bus, not a track */
1710                 return false;
1711         }
1712
1713         playlist = ds->playlist();
1714
1715
1716         TimeSelection time (selection.time);
1717         float speed = ds->speed();
1718         if (speed != 1.0f) {
1719                 for (TimeSelection::iterator i = time.begin(); i != time.end(); ++i) {
1720                         (*i).start = session_frame_to_track_frame((*i).start, speed);
1721                         (*i).end   = session_frame_to_track_frame((*i).end,   speed);
1722                 }
1723         }
1724         
1725         switch (op) {
1726         case Cut:
1727                 _session.add_undo (playlist->get_memento());
1728                 if ((what_we_got = playlist->cut (time)) != 0) {
1729                         editor.get_cut_buffer().add (what_we_got);
1730                         _session.add_redo_no_execute (playlist->get_memento());
1731                         ret = true;
1732                 }
1733                 break;
1734         case Copy:
1735                 if ((what_we_got = playlist->copy (time)) != 0) {
1736                         editor.get_cut_buffer().add (what_we_got);
1737                 }
1738                 break;
1739
1740         case Clear:
1741                 _session.add_undo (playlist->get_memento());
1742                 if ((what_we_got = playlist->cut (time)) != 0) {
1743                         _session.add_redo_no_execute (playlist->get_memento());
1744                         what_we_got->unref ();
1745                         ret = true;
1746                 }
1747                 break;
1748         }
1749
1750         return ret;
1751 }
1752
1753 bool
1754 AudioTimeAxisView::paste (jack_nframes_t pos, float times, Selection& selection, size_t nth)
1755 {
1756         if (!is_audio_track()) {
1757                 return false;
1758         }
1759
1760         Playlist* playlist = get_diskstream()->playlist();
1761         PlaylistSelection::iterator p;
1762         
1763         for (p = selection.playlists.begin(); p != selection.playlists.end() && nth; ++p, --nth);
1764
1765         if (p == selection.playlists.end()) {
1766                 return false;
1767         }
1768
1769         if (get_diskstream()->speed() != 1.0f)
1770                 pos = session_frame_to_track_frame(pos, get_diskstream()->speed() );
1771         
1772         _session.add_undo (playlist->get_memento());
1773         playlist->paste (**p, pos, times);
1774         _session.add_redo_no_execute (playlist->get_memento());
1775
1776         return true;
1777 }
1778
1779 void
1780 AudioTimeAxisView::region_view_added (AudioRegionView* arv)
1781 {
1782         for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
1783                 AutomationTimeAxisView* atv;
1784
1785                 if ((atv = dynamic_cast<AutomationTimeAxisView*> (*i)) != 0) {
1786                         arv->add_ghost (*atv);
1787                 }
1788         }
1789 }
1790
1791 void
1792 AudioTimeAxisView::add_ghost_to_redirect (AudioRegionView* arv, AutomationTimeAxisView* atv)
1793 {
1794         arv->add_ghost (*atv);
1795 }
1796
1797 list<TimeAxisView*>
1798 AudioTimeAxisView::get_child_list()
1799 {
1800   
1801         list<TimeAxisView*>redirect_children;
1802         
1803         for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
1804                 if (!(*i)->hidden()) {
1805                         redirect_children.push_back(*i);
1806                 }
1807         }
1808         return redirect_children;
1809 }
1810
1811
1812 void
1813 AudioTimeAxisView::build_playlist_menu (Gtk::Menu * menu)
1814 {
1815         using namespace Menu_Helpers;
1816
1817         if (!menu || !is_audio_track()) {
1818                 return;
1819         }
1820
1821         MenuList& playlist_items = menu->items();
1822         menu->set_name ("ArdourContextMenu");
1823         playlist_items.clear();
1824
1825         if (playlist_menu) {
1826                 delete playlist_menu;
1827         }
1828         playlist_menu = new Menu;
1829         playlist_menu->set_name ("ArdourContextMenu");
1830
1831         playlist_items.push_back (MenuElem (string_compose (_("Current: %1"), get_diskstream()->playlist()->name())));
1832         playlist_items.push_back (SeparatorElem());
1833         
1834         playlist_items.push_back (MenuElem (_("Rename"), mem_fun(*this, &AudioTimeAxisView::rename_current_playlist)));
1835         playlist_items.push_back (SeparatorElem());
1836
1837         playlist_items.push_back (MenuElem (_("New"), mem_fun(*this, &AudioTimeAxisView::use_new_playlist)));
1838         playlist_items.push_back (MenuElem (_("New Copy"), mem_fun(*this, &AudioTimeAxisView::use_copy_playlist)));
1839         playlist_items.push_back (SeparatorElem());
1840         playlist_items.push_back (MenuElem (_("Clear Current"), mem_fun(*this, &AudioTimeAxisView::clear_playlist)));
1841         playlist_items.push_back (SeparatorElem());
1842         playlist_items.push_back (MenuElem(_("Select"), mem_fun(*this, &AudioTimeAxisView::show_playlist_selector)));
1843
1844 }
1845
1846 void
1847 AudioTimeAxisView::show_playlist_selector ()
1848 {
1849         editor.playlist_selector().show_for (this);
1850 }
1851
1852
1853 void
1854 AudioTimeAxisView::map_frozen ()
1855 {
1856         if (!is_audio_track()) {
1857                 return;
1858         }
1859
1860         ENSURE_GUI_THREAD (mem_fun(*this, &AudioTimeAxisView::map_frozen));
1861
1862
1863         switch (audio_track()->freeze_state()) {
1864         case AudioTrack::Frozen:
1865                 playlist_button.set_sensitive (false);
1866                 rec_enable_button->set_sensitive (false);
1867                 break;
1868         default:
1869                 playlist_button.set_sensitive (true);
1870                 rec_enable_button->set_sensitive (true);
1871                 break;
1872         }
1873 }
1874
1875 void
1876 AudioTimeAxisView::show_all_xfades ()
1877 {
1878         if (view) {
1879                 view->show_all_xfades ();
1880         }
1881 }
1882
1883 void
1884 AudioTimeAxisView::hide_all_xfades ()
1885 {
1886         if (view) {
1887                 view->hide_all_xfades ();
1888         }
1889 }
1890
1891 void
1892 AudioTimeAxisView::hide_dependent_views (TimeAxisViewItem& tavi)
1893 {
1894         AudioRegionView* rv;
1895
1896         if (view && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
1897                 view->hide_xfades_involving (*rv);
1898         }
1899 }
1900
1901 void
1902 AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi)
1903 {
1904         AudioRegionView* rv;
1905
1906         if (view && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
1907                 view->reveal_xfades_involving (*rv);
1908         }
1909 }
1910
1911 void
1912 AudioTimeAxisView::route_active_changed ()
1913 {
1914         RouteUI::route_active_changed ();
1915
1916         if (is_audio_track()) {
1917                 if (_route.active()) {
1918                         controls_ebox.set_name ("AudioTrackControlsBaseUnselected");
1919                         controls_base_selected_name = "AudioTrackControlsBaseSelected";
1920                         controls_base_unselected_name = "AudioTrackControlsBaseUnselected";
1921                 } else {
1922                         controls_ebox.set_name ("AudioTrackControlsBaseInactiveUnselected");
1923                         controls_base_selected_name = "AudioTrackControlsBaseInactiveSelected";
1924                         controls_base_unselected_name = "AudioTrackControlsBaseInactiveUnselected";
1925                 }
1926         } else {
1927                 if (_route.active()) {
1928                         controls_ebox.set_name ("BusControlsBaseUnselected");
1929                         controls_base_selected_name = "BusControlsBaseSelected";
1930                         controls_base_unselected_name = "BusControlsBaseUnselected";
1931                 } else {
1932                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1933                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1934                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1935                 }
1936         }
1937 }
1938
1939 XMLNode* 
1940 AudioTimeAxisView::get_child_xml_node (std::string childname)
1941 {
1942         return RouteUI::get_child_xml_node (childname);
1943 }