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