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