Fix visibility of automation tracks on reloading sessions.
[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/processor.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_line.h"
54 #include "canvas_impl.h"
55 #include "crossfade_view.h"
56 #include "enums.h"
57 #include "automation_time_axis.h"
58 #include "keyboard.h"
59 #include "playlist_selector.h"
60 #include "prompter.h"
61 #include "public_editor.h"
62 #include "audio_region_view.h"
63 #include "simplerect.h"
64 #include "audio_streamview.h"
65 #include "utils.h"
66
67 #include <ardour/audio_track.h>
68
69 #include "i18n.h"
70
71 using namespace ARDOUR;
72 using namespace PBD;
73 using namespace Gtk;
74 using namespace Editing;
75
76 AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas)
77         : AxisView(sess)
78         , RouteTimeAxisView(ed, sess, rt, canvas)
79 {
80         // Make sure things are sane...
81         assert(!is_track() || is_audio_track());
82
83         subplugin_menu.set_name ("ArdourContextMenu");
84         waveform_item = 0;
85
86         _view = new AudioStreamView (*this);
87
88         ignore_toggle = false;
89
90         mute_button->set_active (false);
91         solo_button->set_active (false);
92         
93         if (is_audio_track()) {
94                 controls_ebox.set_name ("AudioTrackControlsBaseUnselected");
95         } else { // bus
96                 controls_ebox.set_name ("AudioBusControlsBaseUnselected");
97         }
98
99         ensure_xml_node ();
100
101         set_state (*xml_node);
102
103         /* if set_state above didn't create a gain automation child, we need to make one */
104         if (automation_track (GainAutomation) == 0) {
105                 create_automation_child (GainAutomation, false);
106         }
107         
108         _route->panner().Changed.connect (bind (mem_fun(*this, &AudioTimeAxisView::ensure_pan_views), false));
109
110         /* map current state of the route */
111
112         processors_changed ();
113         reset_processor_automation_curves ();
114         ensure_pan_views (false);
115         update_control_names ();
116
117         if (is_audio_track()) {
118
119                 /* ask for notifications of any new RegionViews */
120                 _view->RegionViewAdded.connect (mem_fun(*this, &AudioTimeAxisView::region_view_added));
121
122                 if (!editor.have_idled()) {
123                         /* first idle will do what we need */
124                 } else {
125                         first_idle ();
126                 } 
127
128         } else {
129                 post_construct ();
130         }
131 }
132
133 AudioTimeAxisView::~AudioTimeAxisView ()
134 {
135 }
136
137 void
138 AudioTimeAxisView::first_idle ()
139 {
140         _view->attach ();
141         post_construct ();
142 }
143
144 AudioStreamView*
145 AudioTimeAxisView::audio_view()
146 {
147         return dynamic_cast<AudioStreamView*>(_view);
148 }
149
150 guint32
151 AudioTimeAxisView::show_at (double y, int& nth, Gtk::VBox *parent)
152 {
153         ensure_xml_node ();
154         xml_node->add_property ("shown-editor", "yes");
155                 
156         return TimeAxisView::show_at (y, nth, parent);
157 }
158
159 void
160 AudioTimeAxisView::hide ()
161 {
162         ensure_xml_node ();
163         xml_node->add_property ("shown-editor", "no");
164
165         TimeAxisView::hide ();
166 }
167
168
169 void
170 AudioTimeAxisView::append_extra_display_menu_items ()
171 {
172         using namespace Menu_Helpers;
173
174         MenuList& items = display_menu->items();
175
176         // crossfade stuff
177         if (!Profile->get_sae()) {
178                 items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades)));
179                 items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades)));
180         }
181
182         // waveform menu
183         Menu *waveform_menu = manage(new Menu);
184         MenuList& waveform_items = waveform_menu->items();
185         waveform_menu->set_name ("ArdourContextMenu");
186         
187         waveform_items.push_back (CheckMenuElem (_("Show waveforms"), mem_fun(*this, &AudioTimeAxisView::toggle_waveforms)));
188         waveform_item = static_cast<CheckMenuItem *> (&waveform_items.back());
189         ignore_toggle = true;
190         waveform_item->set_active (editor.show_waveforms());
191         ignore_toggle = false;
192
193         waveform_items.push_back (SeparatorElem());
194         
195         RadioMenuItem::Group group;
196         
197         waveform_items.push_back (RadioMenuElem (group, _("Traditional"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Traditional)));
198         traditional_item = static_cast<RadioMenuItem *> (&waveform_items.back());
199
200         if (!Profile->get_sae()) {
201                 waveform_items.push_back (RadioMenuElem (group, _("Rectified"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_shape), Rectified)));
202                 rectified_item = static_cast<RadioMenuItem *> (&waveform_items.back());
203         } else {
204                 rectified_item = 0;
205         }
206
207         waveform_items.push_back (SeparatorElem());
208         
209         RadioMenuItem::Group group2;
210
211         waveform_items.push_back (RadioMenuElem (group2, _("Linear"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_scale), LinearWaveform)));
212         linearscale_item = static_cast<RadioMenuItem *> (&waveform_items.back());
213
214         waveform_items.push_back (RadioMenuElem (group2, _("Logarithmic"), bind (mem_fun(*this, &AudioTimeAxisView::set_waveform_scale), LogWaveform)));
215         logscale_item = static_cast<RadioMenuItem *> (&waveform_items.back());
216
217         // setting initial item state
218         AudioStreamView* asv = audio_view();
219         if (asv) {
220                 ignore_toggle = true;
221                 if (asv->get_waveform_shape() == Rectified && rectified_item) {
222                         rectified_item->set_active(true);
223                 } else {
224                         traditional_item->set_active(true);
225                 }
226
227                 if (asv->get_waveform_scale() == LogWaveform) 
228                         logscale_item->set_active(true);
229                 else linearscale_item->set_active(true);
230                 ignore_toggle = false;
231         }
232
233         items.push_back (MenuElem (_("Waveform"), *waveform_menu));
234
235 }
236         
237 Gtk::Menu*
238 AudioTimeAxisView::build_mode_menu()
239 {
240         using namespace Menu_Helpers;
241
242         Menu* mode_menu = manage (new Menu);
243         MenuList& items = mode_menu->items();
244         mode_menu->set_name ("ArdourContextMenu");
245
246         RadioMenuItem::Group mode_group;
247         items.push_back (RadioMenuElem (mode_group, _("Normal"),
248                                 bind (mem_fun (*this, &AudioTimeAxisView::set_track_mode), ARDOUR::Normal)));
249         normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
250         items.push_back (RadioMenuElem (mode_group, _("Tape"),
251                                 bind (mem_fun (*this, &AudioTimeAxisView::set_track_mode), ARDOUR::Destructive)));
252         destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
253
254         switch (track()->mode()) {
255                 case ARDOUR::Destructive:
256                         destructive_track_mode_item->set_active ();
257                         break;
258                 case ARDOUR::Normal:
259                         normal_track_mode_item->set_active ();
260                         break;
261         }
262
263         return mode_menu;
264 }
265
266 void
267 AudioTimeAxisView::toggle_waveforms ()
268 {
269         AudioStreamView* asv = audio_view();
270         assert(asv);
271
272         if (asv && waveform_item && !ignore_toggle) {
273                 asv->set_show_waveforms (waveform_item->get_active());
274         }
275 }
276
277 void
278 AudioTimeAxisView::set_show_waveforms (bool yn)
279 {
280         AudioStreamView* asv = audio_view();
281         assert(asv);
282
283         if (waveform_item) {
284                 waveform_item->set_active (yn);
285         } else {
286                 asv->set_show_waveforms (yn);
287         }
288 }
289
290 void
291 AudioTimeAxisView::set_show_waveforms_recording (bool yn)
292 {
293         AudioStreamView* asv = audio_view();
294
295         if (asv) {
296                 asv->set_show_waveforms_recording (yn);
297         }
298 }
299
300 void
301 AudioTimeAxisView::set_waveform_shape (WaveformShape shape)
302 {
303         AudioStreamView* asv = audio_view();
304
305         if (asv && !ignore_toggle) {
306                 asv->set_waveform_shape (shape);
307         }
308
309         map_frozen ();
310 }       
311
312 void
313 AudioTimeAxisView::set_waveform_scale (WaveformScale scale)
314 {
315         AudioStreamView* asv = audio_view();
316
317         if (asv && !ignore_toggle) {
318                 asv->set_waveform_scale (scale);
319         }
320
321         map_frozen ();
322 }       
323
324 void
325 AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
326 {
327         if (param.type() == GainAutomation) {
328
329                 boost::shared_ptr<AutomationControl> c = _route->gain_control();
330                 if (!c) {
331                         error << "Route has no gain automation, unable to add automation track view." << endmsg;
332                         return;
333                 }
334
335                 boost::shared_ptr<AutomationTimeAxisView> gain_track(new AutomationTimeAxisView (_session,
336                                 _route, _route, c,
337                                 editor,
338                                 *this,
339                                 false,
340                                 parent_canvas,
341                                 _route->describe_parameter(param)));
342
343                 add_automation_child(Evoral::Parameter(GainAutomation), gain_track, show);
344
345         } else if (param.type() == PanAutomation) {
346
347                 ensure_xml_node ();
348                 ensure_pan_views (show);
349
350         } else {
351                 error << "AudioTimeAxisView: unknown automation child " << EventTypeMap::instance().to_symbol(param) << endmsg;
352         }
353 }
354
355 /** Ensure that we have the appropriate AutomationTimeAxisViews for the
356  *  panners that we have.
357  *
358  *  @param show true to show any new views that we create, otherwise false.
359  */
360 void
361 AudioTimeAxisView::ensure_pan_views (bool show)
362 {
363         const set<Evoral::Parameter>& params = _route->panner().what_can_be_automated();
364         set<Evoral::Parameter>::iterator p;
365
366         for (p = params.begin(); p != params.end(); ++p) {
367                 boost::shared_ptr<ARDOUR::AutomationControl> pan_control
368                         = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
369                                 _route->panner().data().control(*p));
370                 
371                 if (pan_control->parameter().type() == NullAutomation) {
372                         error << "Pan control has NULL automation type!" << endmsg;
373                         continue;
374                 }
375
376                 if (automation_child (pan_control->parameter ()).get () == 0) {
377
378                         /* we don't already have an AutomationTimeAxisView for this parameter */
379
380                         std::string const name = _route->describe_parameter (pan_control->parameter ());
381
382                         boost::shared_ptr<AutomationTimeAxisView> pan_track (
383                                 new AutomationTimeAxisView (_session,
384                                                             _route, _route, pan_control, 
385                                                             editor,
386                                                             *this,
387                                                             false,
388                                                             parent_canvas,
389                                                             name)
390                                 
391                                 );
392                         
393                         add_automation_child (*p, pan_track, show);
394                 }
395         }
396 }
397 #if 0
398 void
399 AudioTimeAxisView::toggle_gain_track ()
400 {
401         bool showit = gain_automation_item->get_active();
402
403         if (showit != gain_track->marked_for_display()) {
404                 if (showit) {
405                         gain_track->set_marked_for_display (true);
406                         gain_track->canvas_display->show();
407                         gain_track->canvas_background->show();
408                         gain_track->get_state_node()->add_property ("shown", X_("yes"));
409                 } else {
410                         gain_track->set_marked_for_display (false);
411                         gain_track->hide ();
412                         gain_track->get_state_node()->add_property ("shown", X_("no"));
413                 }
414
415                 /* now trigger a redisplay */
416                 
417                 if (!no_redraw) {
418                          _route->gui_changed (X_("visible_tracks"), (void *) 0); /* EMIT_SIGNAL */
419                 }
420         }
421 }
422
423 void
424 AudioTimeAxisView::gain_hidden ()
425 {
426         gain_track->get_state_node()->add_property (X_("shown"), X_("no"));
427
428         if (gain_automation_item && !_hidden) {
429                 gain_automation_item->set_active (false);
430         }
431
432          _route->gui_changed ("visible_tracks", (void *) 0); /* EMIT_SIGNAL */
433 }
434
435 void
436 AudioTimeAxisView::toggle_pan_track ()
437 {
438         bool showit = pan_automation_item->get_active();
439
440         if (showit != pan_track->marked_for_display()) {
441                 if (showit) {
442                         pan_track->set_marked_for_display (true);
443                         pan_track->canvas_display->show();
444                         pan_track->canvas_background->show();
445                         pan_track->get_state_node()->add_property ("shown", X_("yes"));
446                 } else {
447                         pan_track->set_marked_for_display (false);
448                         pan_track->hide ();
449                         pan_track->get_state_node()->add_property ("shown", X_("no"));
450                 }
451
452                 /* now trigger a redisplay */
453         }
454 }
455 #endif
456                 
457 void
458 AudioTimeAxisView::show_all_automation ()
459 {
460         no_redraw = true;
461
462         RouteTimeAxisView::show_all_automation ();
463
464         no_redraw = false;
465
466          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
467 }
468
469 void
470 AudioTimeAxisView::show_existing_automation ()
471 {
472         no_redraw = true;
473
474         RouteTimeAxisView::show_existing_automation ();
475
476         no_redraw = false;
477
478          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
479 }
480
481 void
482 AudioTimeAxisView::hide_all_automation ()
483 {
484         no_redraw = true;
485
486         RouteTimeAxisView::hide_all_automation();
487
488         no_redraw = false;
489          _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
490 }
491
492 void
493 AudioTimeAxisView::show_all_xfades ()
494 {
495         AudioStreamView* asv = audio_view();
496
497         if (asv) {
498                 asv->show_all_xfades ();
499         }
500 }
501
502 void
503 AudioTimeAxisView::hide_all_xfades ()
504 {
505         AudioStreamView* asv = audio_view();
506         
507         if (asv) {
508                 asv->hide_all_xfades ();
509         }
510 }
511
512 void
513 AudioTimeAxisView::hide_dependent_views (TimeAxisViewItem& tavi)
514 {
515         AudioStreamView* asv = audio_view();
516         AudioRegionView* rv;
517
518         if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
519                 asv->hide_xfades_involving (*rv);
520         }
521 }
522
523 void
524 AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi)
525 {
526         AudioStreamView* asv = audio_view();
527         AudioRegionView* rv;
528
529         if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
530                 asv->reveal_xfades_involving (*rv);
531         }
532 }
533
534 void
535 AudioTimeAxisView::route_active_changed ()
536 {
537         RouteTimeAxisView::route_active_changed ();
538         update_control_names ();
539 }
540
541
542 /**
543  *    Set up the names of the controls so that they are coloured
544  *    correctly depending on whether this route is inactive or
545  *    selected.
546  */
547
548 void
549 AudioTimeAxisView::update_control_names ()
550 {
551         if (is_audio_track()) {
552                 if (_route->active()) {
553                         controls_base_selected_name = "AudioTrackControlsBaseSelected";
554                         controls_base_unselected_name = "AudioTrackControlsBaseUnselected";
555                 } else {
556                         controls_base_selected_name = "AudioTrackControlsBaseInactiveSelected";
557                         controls_base_unselected_name = "AudioTrackControlsBaseInactiveUnselected";
558                 }
559         } else {
560                 if (_route->active()) {
561                         controls_base_selected_name = "BusControlsBaseSelected";
562                         controls_base_unselected_name = "BusControlsBaseUnselected";
563                 } else {
564                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
565                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
566                 }
567         }
568
569         if (get_selected()) {
570                 controls_ebox.set_name (controls_base_selected_name);
571         } else {
572                 controls_ebox.set_name (controls_base_unselected_name);
573         }
574 }
575