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