Updated translation from Petter Sundlöf
[ardour.git] / gtk2_ardour / audio_time_axis.cc
1 /*
2     Copyright (C) 2000-2006 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 */
19
20 #include <cstdlib>
21 #include <cmath>
22 #include <cassert>
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/memento_command.h>
33
34 #include <gtkmm2ext/gtk_ui.h>
35 #include <gtkmm2ext/selector.h>
36 #include <gtkmm2ext/stop_signal.h>
37 #include <gtkmm2ext/bindable_button.h>
38 #include <gtkmm2ext/utils.h>
39
40 #include <ardour/audioplaylist.h>
41 #include <ardour/audio_diskstream.h>
42 #include <ardour/insert.h>
43 #include <ardour/location.h>
44 #include <ardour/panner.h>
45 #include <ardour/playlist.h>
46 #include <ardour/profile.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 "canvas_impl.h"
56 #include "crossfade_view.h"
57 #include "enums.h"
58 #include "gain_automation_time_axis.h"
59 #include "keyboard.h"
60 #include "pan_automation_time_axis.h"
61 #include "playlist_selector.h"
62 #include "prompter.h"
63 #include "public_editor.h"
64 #include "audio_region_view.h"
65 #include "simplerect.h"
66 #include "audio_streamview.h"
67 #include "utils.h"
68
69 #include <ardour/audio_track.h>
70
71 #include "i18n.h"
72
73 using namespace ARDOUR;
74 using namespace PBD;
75 using namespace Gtk;
76 using namespace Editing;
77
78 AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
79         : AxisView(sess)
80         , RouteTimeAxisView(ed, sess, rt, canvas)
81 {
82         // Make sure things are sane...
83         assert(!is_track() || is_audio_track());
84
85         subplugin_menu.set_name ("ArdourContextMenu");
86         gain_track = 0;
87         pan_track = 0;
88         waveform_item = 0;
89         pan_automation_item = 0;
90         gain_automation_item = 0;
91
92         _view = new AudioStreamView (*this);
93
94         add_gain_automation_child ();
95         add_pan_automation_child ();
96
97         ignore_toggle = false;
98
99         if (is_audio_track())
100                 controls_ebox.set_name ("AudioTimeAxisViewControlsBaseUnselected");
101         else // bus
102                 controls_ebox.set_name ("AudioBusControlsBaseUnselected");
103
104         ensure_xml_node ();
105
106         set_state (*xml_node);
107         
108         _route->panner().Changed.connect (mem_fun(*this, &AudioTimeAxisView::update_pans));
109
110         update_control_names ();
111
112         if (is_audio_track()) {
113
114                 /* ask for notifications of any new RegionViews */
115                 _view->RegionViewAdded.connect (mem_fun(*this, &AudioTimeAxisView::region_view_added));
116
117                 if (!editor.have_idled()) {
118                         /* first idle will do what we need */
119                 } else {
120                         first_idle ();
121                 } 
122
123         } else {
124                 post_construct ();
125         }
126 }
127
128 AudioTimeAxisView::~AudioTimeAxisView ()
129 {
130 }
131
132 void
133 AudioTimeAxisView::first_idle ()
134 {
135         _view->attach ();
136         post_construct ();
137 }
138
139 AudioStreamView*
140 AudioTimeAxisView::audio_view()
141 {
142         return dynamic_cast<AudioStreamView*>(_view);
143 }
144
145 guint32
146 AudioTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
147 {
148         ensure_xml_node ();
149         xml_node->add_property ("shown_editor", "yes");
150                 
151         return TimeAxisView::show_at (y, nth, parent);
152 }
153
154 void
155 AudioTimeAxisView::hide ()
156 {
157         ensure_xml_node ();
158         xml_node->add_property ("shown_editor", "no");
159
160         TimeAxisView::hide ();
161 }
162
163 void
164 AudioTimeAxisView::set_state (const XMLNode& node)
165 {
166         const XMLProperty *prop;
167         
168         TimeAxisView::set_state (node);
169         
170         if ((prop = node.property ("shown_editor")) != 0) {
171                 if (prop->value() == "no") {
172                         _marked_for_display = false;
173                 } else {
174                         _marked_for_display = true;
175                 }
176         } else {
177                 _marked_for_display = true;
178         }
179         
180         XMLNodeList nlist = node.children();
181         XMLNodeConstIterator niter;
182         XMLNode *child_node;
183         
184         
185         show_gain_automation = false;
186         show_pan_automation  = false;
187         
188         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
189                 child_node = *niter;
190
191                 if (child_node->name() == "gain") {
192                         XMLProperty *prop=child_node->property ("shown");
193                         
194                         if (prop != 0) {
195                                 if (prop->value() == "yes") {
196                                         show_gain_automation = true;
197                                 }
198                         }
199                         continue;
200                 }
201                 
202                 if (child_node->name() == "pan") {
203                         XMLProperty *prop=child_node->property ("shown");
204                         
205                         if (prop != 0) {
206                                 if (prop->value() == "yes") {
207                                         show_pan_automation = true;
208                                 }                       
209                         }
210                         continue;
211                 }
212         }
213 }
214
215 void
216 AudioTimeAxisView::build_automation_action_menu ()
217 {
218         using namespace Menu_Helpers;
219
220         RouteTimeAxisView::build_automation_action_menu ();
221
222         MenuList& automation_items = automation_action_menu->items();
223         
224         automation_items.push_back (SeparatorElem());
225
226         automation_items.push_back (CheckMenuElem (_("Fader"), 
227                                                    mem_fun(*this, &AudioTimeAxisView::toggle_gain_track)));
228         gain_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
229         gain_automation_item->set_active(show_gain_automation);
230
231         automation_items.push_back (CheckMenuElem (_("Pan"),
232                                                    mem_fun(*this, &AudioTimeAxisView::toggle_pan_track)));
233         pan_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
234         pan_automation_item->set_active(show_pan_automation);
235         
236 }
237
238 void
239 AudioTimeAxisView::append_extra_display_menu_items ()
240 {
241         using namespace Menu_Helpers;
242
243         MenuList& items = display_menu->items();
244
245         // crossfade stuff
246         if (!Profile->get_sae()) {
247                 items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades)));
248                 items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades)));
249         }
250
251         // waveform menu
252         Menu *waveform_menu = manage(new Menu);
253         MenuList& waveform_items = waveform_menu->items();
254         waveform_menu->set_name ("ArdourContextMenu");
255         
256         waveform_items.push_back (CheckMenuElem (_("Show waveforms"), mem_fun(*this, &AudioTimeAxisView::toggle_waveforms)));
257         waveform_item = static_cast<CheckMenuItem *> (&waveform_items.back());
258         ignore_toggle = true;
259         waveform_item->set_active (editor.show_waveforms());
260         ignore_toggle = false;
261
262         waveform_items.push_back (SeparatorElem());
263         
264         RadioMenuItem::Group group;
265         
266         waveform_items.push_back (RadioMenuElem (group, _("Traditional"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Traditional)));
267         traditional_item = static_cast<RadioMenuItem *> (&waveform_items.back());
268
269         if (!Profile->get_sae()) {
270                 waveform_items.push_back (RadioMenuElem (group, _("Rectified"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Rectified)));
271                 rectified_item = static_cast<RadioMenuItem *> (&waveform_items.back());
272         } else {
273                 rectified_item = 0;
274         }
275
276         waveform_items.push_back (SeparatorElem());
277         
278         RadioMenuItem::Group group2;
279
280         waveform_items.push_back (RadioMenuElem (group2, _("Linear"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_scale), LinearWaveform)));
281         linearscale_item = static_cast<RadioMenuItem *> (&waveform_items.back());
282
283         waveform_items.push_back (RadioMenuElem (group2, _("Logarithmic"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_scale), LogWaveform)));
284         logscale_item = static_cast<RadioMenuItem *> (&waveform_items.back());
285
286         // setting initial item state
287         AudioStreamView* asv = audio_view();
288         if (asv) {
289                 ignore_toggle = true;
290                 if (asv->get_waveform_shape() == Rectified && rectified_item) {
291                         rectified_item->set_active(true);
292                 } else {
293                         traditional_item->set_active(true);
294                 }
295
296                 if (asv->get_waveform_scale() == LogWaveform) 
297                         logscale_item->set_active(true);
298                 else linearscale_item->set_active(true);
299                 ignore_toggle = false;
300         }
301
302         items.push_back (MenuElem (_("Waveform"), *waveform_menu));
303 }
304
305 void
306 AudioTimeAxisView::toggle_waveforms ()
307 {
308         AudioStreamView* asv = audio_view();
309         assert(asv);
310
311         if (asv && waveform_item && !ignore_toggle) {
312                 asv->set_show_waveforms (waveform_item->get_active());
313         }
314 }
315
316 void
317 AudioTimeAxisView::set_show_waveforms (bool yn)
318 {
319         AudioStreamView* asv = audio_view();
320         assert(asv);
321
322         if (waveform_item) {
323                 waveform_item->set_active (yn);
324         } else {
325                 asv->set_show_waveforms (yn);
326         }
327 }
328
329 void
330 AudioTimeAxisView::set_show_waveforms_recording (bool yn)
331 {
332         AudioStreamView* asv = audio_view();
333
334         if (asv) {
335                 asv->set_show_waveforms_recording (yn);
336         }
337 }
338
339 void
340 AudioTimeAxisView::set_waveform_shape (WaveformShape shape)
341 {
342         AudioStreamView* asv = audio_view();
343
344         if (asv && !ignore_toggle) {
345                 asv->set_waveform_shape (shape);
346         }
347
348         map_frozen ();
349 }       
350
351 void
352 AudioTimeAxisView::set_waveform_scale (WaveformScale scale)
353 {
354         AudioStreamView* asv = audio_view();
355
356         if (asv && !ignore_toggle) {
357                 asv->set_waveform_scale (scale);
358         }
359
360         map_frozen ();
361 }       
362
363 void
364 AudioTimeAxisView::add_gain_automation_child ()
365 {
366         XMLProperty* prop;
367         AutomationLine* line;
368
369         gain_track = new GainAutomationTimeAxisView (_session,
370                                                      _route,
371                                                      editor,
372                                                      *this,
373                                                      parent_canvas,
374                                                      _("gain"),
375                                                      _route->gain_automation_curve());
376         
377         line = new AutomationGainLine ("automation gain",
378                                        _session,
379                                        *gain_track,
380                                        *gain_track->canvas_display,
381                                        _route->gain_automation_curve());
382
383         line->set_line_color (ARDOUR_UI::config()->canvasvar_AutomationLine.get());
384         
385
386         gain_track->add_line (*line);
387
388         add_child (gain_track);
389
390         gain_track->Hiding.connect (mem_fun(*this, &AudioTimeAxisView::gain_hidden));
391
392         bool hideit = true;
393         
394         XMLNode* node;
395
396         if ((node = gain_track->get_state_node()) != 0) {
397                 if  ((prop = node->property ("shown")) != 0) {
398                         if (prop->value() == "yes") {
399                                 hideit = false;
400                         }
401                 } 
402         }
403
404         if (hideit) {
405                 gain_track->hide ();
406         }
407 }
408
409 void
410 AudioTimeAxisView::add_pan_automation_child ()
411 {
412         XMLProperty* prop;
413
414         pan_track = new PanAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, _("pan"));
415
416         update_pans ();
417         
418         add_child (pan_track);
419
420         pan_track->Hiding.connect (mem_fun(*this, &AudioTimeAxisView::pan_hidden));
421
422         ensure_xml_node ();
423         bool hideit = true;
424         
425         XMLNode* node;
426
427         if ((node = pan_track->get_state_node()) != 0) {
428                 if ((prop = node->property ("shown")) != 0) {
429                         if (prop->value() == "yes") {
430                                 hideit = false;
431                         }
432                 } 
433         }
434
435         if (hideit) {
436                 pan_track->hide ();
437         }
438 }
439
440 void
441 AudioTimeAxisView::update_pans ()
442 {
443         Panner::iterator p;
444         
445         pan_track->clear_lines ();
446         
447         /* we don't draw lines for "greater than stereo" panning.
448          */
449
450         if (_route->n_outputs() > 2) {
451                 return;
452         }
453
454         for (p = _route->panner().begin(); p != _route->panner().end(); ++p) {
455
456                 AutomationLine* line;
457
458                 line = new AutomationPanLine ("automation pan", _session, *pan_track,
459                                               *pan_track->canvas_display, 
460                                               (*p)->automation());
461
462                 if (p == _route->panner().begin()) {
463                         line->set_line_color (ARDOUR_UI::config()->canvasvar_AutomationLine.get());
464                 } else {
465                         line->set_line_color (ARDOUR_UI::config()->canvasvar_AutomationLine.get());
466                 }
467
468                 pan_track->add_line (*line);
469         }
470 }
471                 
472 void
473 AudioTimeAxisView::toggle_gain_track ()
474 {
475         bool showit = gain_automation_item->get_active();
476
477         if (showit != gain_track->marked_for_display()) {
478                 if (showit) {
479                         gain_track->set_marked_for_display (true);
480                         gain_track->canvas_display->show();
481                         gain_track->get_state_node()->add_property ("shown", X_("yes"));
482                 } else {
483                         gain_track->set_marked_for_display (false);
484                         gain_track->hide ();
485                         gain_track->get_state_node()->add_property ("shown", X_("no"));
486                 }
487
488                 /* now trigger a redisplay */
489                 
490                 if (!no_redraw) {
491                          _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
492                 }
493         }
494 }
495
496 void
497 AudioTimeAxisView::gain_hidden ()
498 {
499         gain_track->get_state_node()->add_property (X_("shown"), X_("no"));
500
501         if (gain_automation_item && !_hidden) {
502                 gain_automation_item->set_active (false);
503         }
504
505          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
506 }
507
508 void
509 AudioTimeAxisView::toggle_pan_track ()
510 {
511         bool showit = pan_automation_item->get_active();
512
513         if (showit != pan_track->marked_for_display()) {
514                 if (showit) {
515                         pan_track->set_marked_for_display (true);
516                         pan_track->canvas_display->show();
517                         pan_track->get_state_node()->add_property ("shown", X_("yes"));
518                 } else {
519                         pan_track->set_marked_for_display (false);
520                         pan_track->hide ();
521                         pan_track->get_state_node()->add_property ("shown", X_("no"));
522                 }
523
524                 /* now trigger a redisplay */
525                 
526                 if (!no_redraw) {
527                          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
528                 }
529         }
530 }
531
532 void
533 AudioTimeAxisView::pan_hidden ()
534 {
535         pan_track->get_state_node()->add_property ("shown", "no");
536
537         if (pan_automation_item && !_hidden) {
538                 pan_automation_item->set_active (false);
539         }
540
541          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
542 }
543
544 void
545 AudioTimeAxisView::show_all_automation ()
546 {
547         no_redraw = true;
548
549         pan_automation_item->set_active (true);
550         gain_automation_item->set_active (true);
551         
552         RouteTimeAxisView::show_all_automation ();
553
554         no_redraw = false;
555
556          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
557 }
558
559 void
560 AudioTimeAxisView::show_existing_automation ()
561 {
562         no_redraw = true;
563
564         pan_automation_item->set_active (true);
565         gain_automation_item->set_active (true);
566
567         RouteTimeAxisView::show_existing_automation ();
568
569         no_redraw = false;
570
571          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
572 }
573
574 void
575 AudioTimeAxisView::hide_all_automation ()
576 {
577         no_redraw = true;
578
579         pan_automation_item->set_active (false);
580         gain_automation_item->set_active (false);
581
582         RouteTimeAxisView::hide_all_automation();
583
584         no_redraw = false;
585          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
586 }
587
588 void
589 AudioTimeAxisView::show_all_xfades ()
590 {
591         AudioStreamView* asv = audio_view();
592
593         if (asv) {
594                 asv->show_all_xfades ();
595         }
596 }
597
598 void
599 AudioTimeAxisView::hide_all_xfades ()
600 {
601         AudioStreamView* asv = audio_view();
602         
603         if (asv) {
604                 asv->hide_all_xfades ();
605         }
606 }
607
608 void
609 AudioTimeAxisView::hide_dependent_views (TimeAxisViewItem& tavi)
610 {
611         AudioStreamView* asv = audio_view();
612         AudioRegionView* rv;
613
614         if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
615                 asv->hide_xfades_involving (*rv);
616         }
617 }
618
619 void
620 AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi)
621 {
622         AudioStreamView* asv = audio_view();
623         AudioRegionView* rv;
624
625         if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
626                 asv->reveal_xfades_involving (*rv);
627         }
628 }
629
630 void
631 AudioTimeAxisView::route_active_changed ()
632 {
633         RouteTimeAxisView::route_active_changed ();
634         update_control_names ();
635 }
636
637
638 /**
639  *    Set up the names of the controls so that they are coloured
640  *    correctly depending on whether this route is inactive or
641  *    selected.
642  */
643
644 void
645 AudioTimeAxisView::update_control_names ()
646 {
647         if (is_audio_track()) {
648                 if (_route->active()) {
649                         controls_base_selected_name = "AudioTrackControlsBaseSelected";
650                         controls_base_unselected_name = "AudioTrackControlsBaseUnselected";
651                 } else {
652                         controls_base_selected_name = "AudioTrackControlsBaseInactiveSelected";
653                         controls_base_unselected_name = "AudioTrackControlsBaseInactiveUnselected";
654                 }
655         } else {
656                 if (_route->active()) {
657                         controls_base_selected_name = "BusControlsBaseSelected";
658                         controls_base_unselected_name = "BusControlsBaseUnselected";
659                 } else {
660                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
661                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
662                 }
663         }
664
665         if (get_selected()) {
666                 controls_ebox.set_name (controls_base_selected_name);
667         } else {
668                 controls_ebox.set_name (controls_base_unselected_name);
669         }
670 }
671
672 XMLNode* 
673 AudioTimeAxisView::get_child_xml_node (const string & childname)
674 {
675         return RouteUI::get_child_xml_node (childname);
676 }
677