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