Gnome::Canvas -> ArdourCanvas and some other small fixes
[ardour.git] / gtk2_ardour / regionview.cc
1 /*
2     Copyright (C) 2001 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 <cmath>
22 #include <algorithm>
23
24 #include <gtkmm.h>
25
26 #include <gtkmm2ext/gtk_ui.h>
27
28 #include <ardour/playlist.h>
29 #include <ardour/audioregion.h>
30 #include <ardour/sndfilesource.h>
31 #include <ardour/diskstream.h>
32
33 #include "streamview.h"
34 #include "regionview.h"
35 #include "audio_time_axis.h"
36 #include "simplerect.h"
37 #include "simpleline.h"
38 #include "waveview.h"
39 #include "public_editor.h"
40 #include "region_editor.h"
41 #include "region_gain_line.h"
42 #include "ghostregion.h"
43 #include "audio_time_axis.h"
44 #include "utils.h"
45 #include "rgb_macros.h"
46 #include "gui_thread.h"
47
48 #include "i18n.h"
49
50 using namespace sigc;
51 using namespace ARDOUR;
52 using namespace Editing;
53 using namespace ArdourCanvas;
54
55 static const int32_t sync_mark_width = 9;
56
57 sigc::signal<void,AudioRegionView*> AudioRegionView::AudioRegionViewGoingAway;
58
59 AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, AudioTimeAxisView &tv, 
60                                   AudioRegion& r, 
61                                   double spu, 
62                                   double amplitude_above_axis,
63                                   Gdk::Color& basic_color,
64                                   bool wfw)
65
66         : TimeAxisViewItem (r.name(), *parent, tv, spu, basic_color, r.position(), r.length(),
67                             TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText|
68                                                           TimeAxisViewItem::ShowNameHighlight|
69                                                           TimeAxisViewItem::ShowFrame)),
70
71           region (r)
72 {
73         ArdourCanvas::Points shape;
74         XMLNode *node;
75
76         editor = 0;
77         valid = true;
78         in_destructor = false;
79         _amplitude_above_axis = amplitude_above_axis;
80         zero_line = 0;
81         wait_for_waves = wfw;
82         _height = 0;
83
84         _flags = 0;
85
86         if ((node = region.extra_xml ("GUI")) != 0) {
87                 set_flags (node);
88         } else {
89                 _flags = WaveformVisible;
90                 store_flags ();
91         }
92
93         if (trackview.editor.new_regionviews_display_gain()) {
94                 _flags |= EnvelopeVisible;
95         }
96
97         compute_colors (basic_color);
98
99         create_waves ();
100
101         gtk_object_set_data (GTK_OBJECT(name_highlight), "regionview", this);
102         gtk_object_set_data (GTK_OBJECT(name_text), "regionview", this);
103
104         //      shape = new ArdourCanvas::Points ();
105
106         /* an equilateral triangle */
107
108         shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1));
109         shape.push_back (Gnome::Art::Point ((sync_mark_width - 1)/2, 1));
110         shape.push_back (Gnome::Art::Point (0, sync_mark_width - 1));
111         shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1));
112
113         sync_mark =  new ArdourCanvas::Polygon (*group);
114         sync_mark->property_points().set_value(shape);
115         sync_mark->set_property ("fill_color_rgba", fill_color);
116         sync_mark->hide();
117
118         fade_in_shape = new ArdourCanvas::Polygon (*group);
119         fade_in_shape->set_property ("fill_color_rgba", fade_color);
120         fade_in_shape->set_data ("regionview", this);
121         
122         fade_out_shape = new ArdourCanvas::Polygon (*group);
123         fade_out_shape->set_property ("fill_color_rgba", fade_color);
124         fade_out_shape->set_data ("regionview", this);
125         
126
127
128         {
129                         uint32_t r,g,b,a;
130                         UINT_TO_RGBA(fill_color,&r,&g,&b,&a);
131         
132
133         fade_in_handle = new ArdourCanvas::SimpleRect (*group);
134         fade_in_handle->set_property ("fill_color_rgba", RGBA_TO_UINT(r,g,b,0));
135         fade_in_handle->set_property ("outline_pixels", 0);
136         fade_in_handle->set_property ("y1", 2.0);
137         fade_in_handle->set_property ("y2", 7.0);
138
139         fade_in_handle->set_data ("regionview", this);
140         
141         fade_out_handle = new ArdourCanvas::SimpleRect (*group);
142         fade_out_handle->set_property ("fill_color_rgba", RGBA_TO_UINT(r,g,b,0));
143         fade_out_handle->set_property ("outline_pixels", 0);
144         fade_out_handle->set_property ("y1", 2.0);
145         fade_out_handle->set_property ("y2", 7.0);
146
147         gtk_object_set_data (GTK_OBJECT(fade_out_handle), "regionview", this);
148         }
149
150         string foo = region.name();
151         foo += ':';
152         foo += "gain";
153
154         gain_line = new AudioRegionGainLine (foo, tv.session(), *this, *group, region.envelope(),
155                                              PublicEditor::canvas_control_point_event,
156                                              PublicEditor::canvas_line_event);
157
158         if (!(_flags & EnvelopeVisible)) {
159                 gain_line->hide ();
160         } else {
161                 gain_line->show ();
162         }
163
164         reset_width_dependent_items ((double) region.length() / samples_per_unit);
165
166         gain_line->reset ();
167
168         set_height (trackview.height);
169
170         region_muted ();
171         region_sync_changed ();
172         region_resized (BoundsChanged);
173         set_waveview_data_src();
174         region_locked ();
175         envelope_active_changed ();
176         fade_in_active_changed ();
177         fade_out_active_changed ();
178
179         region.StateChanged.connect (mem_fun(*this, &AudioRegionView::region_changed));
180
181         group->signal_event().connect (bind (mem_fun (editor, &PublicEditor::UNC (PublicEditor::canvas_region_view_event)), group, this));
182         region_view_name_highlight->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_region_view_name_highlight_event), region_view_name_highlight, this));
183         fade_in_shape->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_fade_in_event), fade_in_shape, this));
184
185         fade_in_handle->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_fade_in_handle_event), fade_in_handle, this));
186         fade_out_shape->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_fade_out_event), fade_out_shape, this));
187         fade_out_handle->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_fade_out_handle_event), fade_out_handle, this));
188
189         set_colors ();
190
191         /* XXX sync mark drag? */
192
193 }
194
195 AudioRegionView::~AudioRegionView ()
196 {
197         in_destructor = true;
198
199         AudioRegionViewGoingAway (this); /* EMIT_SIGNAL */
200
201         for (vector<GnomeCanvasWaveViewCache *>::iterator cache = wave_caches.begin(); cache != wave_caches.end() ; ++cache) {
202                 gnome_canvas_waveview_cache_destroy (*cache);
203         }
204
205         /* all waveviews will be destroyed when the group is destroyed */
206
207         for (vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
208                 delete *g;
209         }
210
211         if (editor) {
212                 delete editor;
213         }
214
215         delete gain_line;
216 }
217
218 gint
219 AudioRegionView::_lock_toggle (ArdourCanvas::Item* item, GdkEvent* ev, void* arg)
220 {
221         switch (ev->type) {
222         case GDK_BUTTON_RELEASE:
223                 static_cast<AudioRegionView*>(arg)->lock_toggle ();
224                 return TRUE;
225                 break;
226         default:
227                 break;
228         } 
229         return FALSE;
230 }
231
232 void
233 AudioRegionView::lock_toggle ()
234 {
235         region.set_locked (!region.locked());
236 }
237
238 void
239 AudioRegionView::region_changed (Change what_changed)
240 {
241         ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionView::region_changed), what_changed));
242
243         if (what_changed & BoundsChanged) {
244                 region_resized (what_changed);
245                 region_sync_changed ();
246         }
247         if (what_changed & Region::MuteChanged) {
248                 region_muted ();
249         }
250         if (what_changed & Region::OpacityChanged) {
251                 region_opacity ();
252         }
253         if (what_changed & ARDOUR::NameChanged) {
254                 region_renamed ();
255         }
256         if (what_changed & Region::SyncOffsetChanged) {
257                 region_sync_changed ();
258         }
259         if (what_changed & Region::LayerChanged) {
260                 region_layered ();
261         }
262         if (what_changed & Region::LockChanged) {
263                 region_locked ();
264         }
265         if (what_changed & AudioRegion::ScaleAmplitudeChanged) {
266                 region_scale_amplitude_changed ();
267         }
268         if (what_changed & AudioRegion::FadeInChanged) {
269                 fade_in_changed ();
270         }
271         if (what_changed & AudioRegion::FadeOutChanged) {
272                 fade_out_changed ();
273         }
274         if (what_changed & AudioRegion::FadeInActiveChanged) {
275                 fade_in_active_changed ();
276         }
277         if (what_changed & AudioRegion::FadeOutActiveChanged) {
278                 fade_out_active_changed ();
279         }
280         if (what_changed & AudioRegion::EnvelopeActiveChanged) {
281                 envelope_active_changed ();
282         }
283 }
284
285 void
286 AudioRegionView::fade_in_changed ()
287 {
288         reset_fade_in_shape ();
289 }
290
291 void
292 AudioRegionView::fade_out_changed ()
293 {
294         reset_fade_out_shape ();
295 }
296
297 void
298 AudioRegionView::set_fade_in_active (bool yn)
299 {
300         region.set_fade_in_active (yn);
301 }
302
303 void
304 AudioRegionView::set_fade_out_active (bool yn)
305 {
306         region.set_fade_out_active (yn);
307 }
308
309 void
310 AudioRegionView::fade_in_active_changed ()
311 {
312         uint32_t r,g,b,a;
313         uint32_t col;
314         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
315
316         if (region.fade_in_active()) {
317                 col = RGBA_TO_UINT(r,g,b,120);
318                 fade_in_shape->set_property ("fill_color_rgba", col);
319                 fade_in_shape->set_property ("width_pixels", 0);
320                 fade_in_shape->set_property ("outline_color_rgba", RGBA_TO_UINT(r,g,b,0));
321         } else { 
322                 col = RGBA_TO_UINT(r,g,b,0);
323                 fade_in_shape->set_property ("fill_color_rgba", col);
324                 fade_in_shape->set_property ("width_pixels", 1);
325                 fade_in_shape->set_property ("outline_color_rgba", RGBA_TO_UINT(r,g,b,255));
326         }
327 }
328
329 void
330 AudioRegionView::fade_out_active_changed ()
331 {
332         uint32_t r,g,b,a;
333         uint32_t col;
334         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
335
336         if (region.fade_out_active()) {
337                 col = RGBA_TO_UINT(r,g,b,120);
338                 fade_out_shape->set_property ("fill_color_rgba", col);
339                 fade_out_shape->set_property ("width_pixels", 0);
340                 fade_out_shape->set_property ("outline_color_rgba", RGBA_TO_UINT(r,g,b,0));
341         } else { 
342                 col = RGBA_TO_UINT(r,g,b,0);
343                 fade_out_shape->set_property ("fill_color_rgba", col);
344                 fade_out_shape->set_property ("width_pixels", 1);
345                 fade_out_shape->set_property ("outline_color_rgba", RGBA_TO_UINT(r,g,b,255));
346         }
347 }
348
349
350 void
351 AudioRegionView::region_scale_amplitude_changed ()
352 {
353         ENSURE_GUI_THREAD (mem_fun(*this, &AudioRegionView::region_scale_amplitude_changed));
354
355         for (uint32_t n = 0; n < waves.size(); ++n) {
356                 // force a reload of the cache
357                 waves[n]->property_data_src().set_value(&region);
358         }
359 }
360
361 void
362 AudioRegionView::region_locked ()
363 {
364         /* name will show locked status */
365         region_renamed ();
366 }
367
368 void
369 AudioRegionView::region_resized (Change what_changed)
370 {
371         double unit_length;
372
373         if (what_changed & ARDOUR::PositionChanged) {
374                 set_position (region.position(), 0);
375         }
376
377         if (what_changed & Change (StartChanged|LengthChanged)) {
378
379                 set_duration (region.length(), 0);
380
381                 unit_length = region.length() / samples_per_unit;
382                 
383                 reset_width_dependent_items (unit_length);
384                 
385                 for (uint32_t n = 0; n < waves.size(); ++n) {
386                         waves[n]->property_region_start().set_value(region.start());
387                 }
388                 
389                 for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
390
391                         (*i)->set_duration (unit_length);
392
393                         for (vector<WaveView*>::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) {
394                                 (*w)->property_region_start().set_value(region.start());
395                         }
396                 }
397         }
398 }
399
400 void
401 AudioRegionView::reset_width_dependent_items (double pixel_width)
402 {
403         TimeAxisViewItem::reset_width_dependent_items (pixel_width);
404         _pixel_width = pixel_width;
405
406         if (zero_line) {
407                 zero_line->set_property ("x2", pixel_width - 1.0);
408         }
409
410         if (pixel_width <= 6.0) {
411                 fade_in_handle->hide();
412                 fade_out_handle->hide();
413         } else {
414                 if (_height < 5.0) {
415                         fade_in_handle->hide();
416                         fade_out_handle->hide();
417                 } else {
418                         fade_in_handle->show();
419                         fade_out_handle->show();
420                 }
421         }
422
423         reset_fade_shapes ();
424 }
425
426 void
427 AudioRegionView::region_layered ()
428 {
429         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (&get_time_axis_view());
430         atv->view->region_layered (this);
431 }
432         
433 void
434 AudioRegionView::region_muted ()
435 {
436         set_frame_color ();
437         region_renamed ();
438
439         for (uint32_t n=0; n < waves.size(); ++n) {
440                 if (region.muted()) {
441                         waves[n]->property_wave_color().set_value(color_map[cMutedWaveForm]);
442                 } else {
443                         waves[n]->property_wave_color().set_value(color_map[cWaveForm]);
444                 }
445         }
446 }
447
448 void
449 AudioRegionView::region_opacity ()
450 {
451         set_frame_color ();
452 }
453
454 void
455 AudioRegionView::raise ()
456 {
457         region.raise ();
458 }
459
460 void
461 AudioRegionView::raise_to_top ()
462 {
463         region.raise_to_top ();
464 }
465
466 void
467 AudioRegionView::lower ()
468 {
469         region.lower ();
470 }
471
472 void
473 AudioRegionView::lower_to_bottom ()
474 {
475         region.lower_to_bottom ();
476 }
477
478 bool
479 AudioRegionView::set_position (jack_nframes_t pos, void* src, double* ignored)
480 {
481         double delta;
482         bool ret;
483
484         if (!(ret = TimeAxisViewItem::set_position (pos, this, &delta))) {
485                 return false;
486         }
487
488         if (ignored) {
489                 *ignored = delta;
490         }
491
492         if (delta) {
493                 for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
494                         (*i)->group->move (delta, 0.0);
495                 }
496         }
497
498         return ret;
499 }
500
501 void
502 AudioRegionView::set_height (gdouble height)
503 {
504         uint32_t wcnt = waves.size();
505
506         TimeAxisViewItem::set_height (height - 2);
507         
508         _height = height;
509
510         for (uint32_t n=0; n < wcnt; ++n) {
511                 gdouble ht;
512
513                 if ((height) < NAME_HIGHLIGHT_THRESH) {
514                         ht = ((height-2*wcnt) / (double) wcnt);
515                 } else {
516                         ht = (((height-2*wcnt) - NAME_HIGHLIGHT_SIZE) / (double) wcnt);
517                 }
518                 
519                 gdouble yoff = n * (ht+1);
520                 
521                 waves[n]->property_height().set_value(ht);
522                 waves[n]->property_y().set_value(yoff + 2);
523         }
524
525         if ((height/wcnt) < NAME_HIGHLIGHT_SIZE) {
526                 gain_line->hide ();
527         } else {
528                 if (_flags & EnvelopeVisible) {
529                         gain_line->show ();
530                 }
531         }
532
533         manage_zero_line ();
534         gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE));
535         reset_fade_shapes ();
536
537         name_text->raise_to_top();
538 }
539
540 void
541 AudioRegionView::manage_zero_line ()
542 {
543         if (!zero_line) {
544                 return;
545         }
546
547         if (_height >= 100) {
548                 gdouble wave_midpoint = (_height - NAME_HIGHLIGHT_SIZE) / 2.0;
549                 zero_line->set_property ("y1", wave_midpoint);
550                 zero_line->set_property ("y2", wave_midpoint);
551                 zero_line->show();
552         } else {
553                 zero_line->hide();
554         }
555 }
556
557 void
558 AudioRegionView::reset_fade_shapes ()
559 {
560         reset_fade_in_shape ();
561         reset_fade_out_shape ();
562 }
563
564 void
565 AudioRegionView::reset_fade_in_shape ()
566 {
567         reset_fade_in_shape_width ((jack_nframes_t) region.fade_in().back()->when);
568 }
569         
570 void
571 AudioRegionView::reset_fade_in_shape_width (jack_nframes_t width)
572 {
573         /* smallest size for a fade is 64 frames */
574
575         width = std::max ((jack_nframes_t) 64, width);
576
577         Points* points;
578         double pwidth = width / samples_per_unit;
579         uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth);
580         double h; 
581         
582         if (_height < 5) {
583                 fade_in_shape->hide();
584                 fade_in_handle->hide();
585                 return;
586         }
587
588         double handle_center;
589         handle_center = pwidth;
590         
591         if (handle_center > 7.0) {
592                 handle_center -= 3.0;
593         } else {
594                 handle_center = 3.0;
595         }
596         
597         fade_in_handle->set_property ("x1",  handle_center - 3.0);
598         fade_in_handle->set_property ("x2",  handle_center + 3.0);
599         
600         if (pwidth < 5) {
601                 fade_in_shape->hide();
602                 return;
603         }
604
605         fade_in_shape->show();
606
607         float curve[npoints];
608         region.fade_in().get_vector (0, region.fade_in().back()->when, curve, npoints);
609
610         points = get_canvas_points ("fade in shape", npoints+3);
611
612         if (_height > NAME_HIGHLIGHT_THRESH) {
613                 h = _height - NAME_HIGHLIGHT_SIZE;
614         } else {
615                 h = _height;
616         }
617
618         /* points *MUST* be in anti-clockwise order */
619
620         uint32_t pi, pc;
621         double xdelta = pwidth/npoints;
622
623         for (pi = 0, pc = 0; pc < npoints; ++pc) {
624                 (*points)[pi].set_x(1 + (pc * xdelta));
625                 (*points)[pi++].set_y(2 + (h - (curve[pc] * h)));
626         }
627         
628         /* fold back */
629
630         (*points)[pi].set_x(pwidth);
631         (*points)[pi++].set_y(2);
632
633         (*points)[pi].set_x(1);
634         (*points)[pi++].set_y(2);
635
636         /* connect the dots ... */
637
638         (*points)[pi] = (*points)[0];
639         
640         fade_in_shape->property_points().set_value(*points);
641         delete points;
642 }
643
644 void
645 AudioRegionView::reset_fade_out_shape ()
646 {
647         reset_fade_out_shape_width ((jack_nframes_t) region.fade_out().back()->when);
648 }
649
650 void
651 AudioRegionView::reset_fade_out_shape_width (jack_nframes_t width)
652 {       
653         /* smallest size for a fade is 64 frames */
654
655         width = std::max ((jack_nframes_t) 64, width);
656
657         Points* points;
658         double pwidth = width / samples_per_unit;
659         uint32_t npoints = std::min (gdk_screen_width(), (int) pwidth);
660         double h;
661
662         if (_height < 5) {
663                 fade_out_shape->hide();
664                 fade_out_handle->hide();
665                 return;
666         }
667
668         double handle_center;
669         handle_center = (region.length() - width) / samples_per_unit;
670         
671         if (handle_center > 7.0) {
672                 handle_center -= 3.0;
673         } else {
674                 handle_center = 3.0;
675         }
676         
677         fade_out_handle->set_property ("x1",  handle_center - 3.0);
678         fade_out_handle->set_property ("x2",  handle_center + 3.0);
679
680         /* don't show shape if its too small */
681         
682         if (pwidth < 5) {
683                 fade_out_shape->hide();
684                 return;
685         } 
686         
687         fade_out_shape->show();
688
689         float curve[npoints];
690         region.fade_out().get_vector (0, region.fade_out().back()->when, curve, npoints);
691
692         if (_height > NAME_HIGHLIGHT_THRESH) {
693                 h = _height - NAME_HIGHLIGHT_SIZE;
694         } else {
695                 h = _height;
696         }
697
698         /* points *MUST* be in anti-clockwise order */
699
700         points = get_canvas_points ("fade out shape", npoints+3);
701
702         uint32_t pi, pc;
703         double xdelta = pwidth/npoints;
704
705         for (pi = 0, pc = 0; pc < npoints; ++pc) {
706                 (*points)[pi] = _pixel_width - 1 - pwidth + (pc*xdelta);
707                 (*points)[pi++] = 2 + (h - (curve[pc] * h));
708         }
709         
710         /* fold back */
711
712         (*points)[pi] = _pixel_width;
713         (*points)[pi++] = h;
714
715         (*points)[pi] = _pixel_width;
716         (*points)[pi++] = 2;
717
718         /* connect the dots ... */
719
720         (*points)[pi] = (*points)[0];
721
722         fade_out_shape->set_property ("points", *points);
723         delete points;
724 }
725
726 void
727 AudioRegionView::set_samples_per_unit (gdouble spu)
728 {
729         TimeAxisViewItem::set_samples_per_unit (spu);
730
731         for (uint32_t n=0; n < waves.size(); ++n) {
732                 waves[n]->property_samples_per_unit().set_value(spu);
733         }
734
735         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
736                 (*i)->set_samples_per_unit (spu);
737                 (*i)->set_duration (region.length() / samples_per_unit);
738         }
739
740         gain_line->reset ();
741         reset_fade_shapes ();
742         region_sync_changed ();
743 }
744
745 bool
746 AudioRegionView::set_duration (jack_nframes_t frames, void *src)
747 {
748         if (!TimeAxisViewItem::set_duration (frames, src)) {
749                 return false;
750         }
751         
752         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
753                 (*i)->set_duration (region.length() / samples_per_unit);
754         }
755
756         return true;
757 }
758
759 void
760 AudioRegionView::set_amplitude_above_axis (gdouble spp)
761 {
762         for (uint32_t n=0; n < waves.size(); ++n) {
763                 waves[n]->property_amplitude_above_axis().set_value(spp);
764         }
765 }
766
767 void
768 AudioRegionView::compute_colors (Gdk::Color& basic_color)
769 {
770         TimeAxisViewItem::compute_colors (basic_color);
771         uint32_t r, g, b, a;
772
773         /* gain color computed in envelope_active_changed() */
774
775         UINT_TO_RGBA (fill_color, &r, &g, &b, &a);
776         fade_color = RGBA_TO_UINT(r,g,b,120);
777 }
778
779 void
780 AudioRegionView::set_colors ()
781 {
782         TimeAxisViewItem::set_colors ();
783         
784         gain_line->set_line_color (region.envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]);
785         sync_mark->set_property ("fill_color_rgba", fill_color);
786
787         for (uint32_t n=0; n < waves.size(); ++n) {
788                 if (region.muted()) {
789                         waves[n]->property_wave_color().set_value(color_map[cMutedWaveForm]);
790                 } else {
791                         waves[n]->property_wave_color().set_value(color_map[cWaveForm]);
792                 }
793         }
794 }
795
796 void
797 AudioRegionView::set_frame_color ()
798 {
799         if (region.opaque()) {
800                 fill_opacity = 180;
801         } else {
802                 fill_opacity = 100;
803         }
804
805         TimeAxisViewItem::set_frame_color ();
806 }
807
808 void
809 AudioRegionView::show_region_editor ()
810 {
811         if (editor == 0) {
812                 editor = new AudioRegionEditor (trackview.session(), region, *this);
813                 // GTK2FIX : how to ensure float without realizing
814                 // editor->realize ();
815                 // trackview.editor.ensure_float (*editor);
816         } 
817
818         editor->show_all ();
819         editor->get_window()->raise();
820 }
821
822 void
823 AudioRegionView::hide_region_editor()
824 {
825         if (editor) {
826                 editor->hide_all ();
827         }
828 }
829
830 void
831 AudioRegionView::region_renamed ()
832 {
833         string str;
834
835         if (region.locked()) {
836                 str += '>';
837                 str += region.name();
838                 str += '<';
839         } else {
840                 str = region.name();
841         }
842
843         if (region.muted()) {
844                 str = string ("!") + str;
845         }
846
847         set_item_name (region.name(), this);
848         set_name_text (str);
849 }
850
851 void
852 AudioRegionView::region_sync_changed ()
853 {
854         int sync_dir;
855         jack_nframes_t sync_offset;
856
857         sync_offset = region.sync_offset (sync_dir);
858
859         /* this has to handle both a genuine change of position, a change of samples_per_unit,
860            and a change in the bounds of the region.
861          */
862
863         if (sync_offset == 0) {
864
865                 /* no sync mark - its the start of the region */
866
867                 sync_mark->hide();
868
869         } else {
870
871                 if ((sync_dir < 0) || ((sync_dir > 0) && (sync_offset > region.length()))) { 
872
873                         /* no sync mark - its out of the bounds of the region */
874
875                         sync_mark->hide();
876
877                 } else {
878
879                         /* lets do it */
880
881                         Points points;
882                         
883                         points = sync_mark->property_points().get_value();
884                         
885                         double offset = sync_offset / samples_per_unit;
886                         
887                         points[0].set_x(offset - ((sync_mark_width-1)/2));
888                         points[0].set_y(1);
889                         
890                         points[1].set_x(offset + (sync_mark_width-1)/2);
891                         points[1].set_y(1);
892                         
893                         points[2].set_x(offset);
894                         points[2].set_y(sync_mark_width - 1);
895                         
896                         points[3].set_x(offset - ((sync_mark_width-1)/2));
897                         points[3].set_y(1);
898                         
899                         sync_mark->show();
900                         sync_mark->property_points().set_value(points);
901
902                 }
903         }
904 }
905
906 void
907 AudioRegionView::set_waveform_visible (bool yn)
908 {
909         if (((_flags & WaveformVisible) != yn)) {
910                 if (yn) {
911                         for (uint32_t n=0; n < waves.size(); ++n) {
912                                 waves[n]->show();
913                         }
914                         _flags |= WaveformVisible;
915                 } else {
916                         for (uint32_t n=0; n < waves.size(); ++n) {
917                                 waves[n]->hide();
918                         }
919                         _flags &= ~WaveformVisible;
920                 }
921                 store_flags ();
922         }
923 }
924
925 void
926 AudioRegionView::temporarily_hide_envelope ()
927 {
928         gain_line->hide ();
929 }
930
931 void
932 AudioRegionView::unhide_envelope ()
933 {
934         if (_flags & EnvelopeVisible) {
935                 gain_line->show ();
936         }
937 }
938
939 void
940 AudioRegionView::set_envelope_visible (bool yn)
941 {
942         if ((_flags & EnvelopeVisible) != yn) {
943                 if (yn) {
944                         gain_line->show ();
945                         _flags |= EnvelopeVisible;
946                 } else {
947                         gain_line->hide ();
948                         _flags &= ~EnvelopeVisible;
949                 }
950                 store_flags ();
951         }
952 }
953
954 void
955 AudioRegionView::create_waves ()
956 {
957         bool create_zero_line = true;
958
959         AudioTimeAxisView& atv (*(dynamic_cast<AudioTimeAxisView*>(&trackview))); // ick
960
961         if (!atv.get_diskstream()) {
962                 return;
963         }
964
965         uint32_t nchans = atv.get_diskstream()->n_channels();
966         
967 //      if (wait_for_waves) {
968                 /* in tmp_waves, set up null pointers for each channel so the vector is allocated */
969                 for (uint32_t n = 0; n < nchans; ++n) {
970                         tmp_waves.push_back (0);
971                 }
972 //      }
973         
974         for (uint32_t n = 0; n < nchans; ++n) {
975                 
976                 if (n >= region.n_channels()) {
977                         break;
978                 }
979                 
980                 wave_caches.push_back (WaveView::create_cache ());
981
982                 if (wait_for_waves) {
983                         if (region.source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n))) {
984                                 create_one_wave (n, true);
985                         } else {
986                                 create_zero_line = false;
987                         }
988                 } else {
989                         create_one_wave (n, true);
990                 }
991         }
992
993         if (create_zero_line) {
994                 zero_line = new ArdourCanvas::Line (*group);
995                 zero_line->set_property ("x1", (gdouble) 1.0);
996                 zero_line->set_property ("x2", (gdouble) (region.length() / samples_per_unit) - 1.0);
997                 zero_line->set_property ("color_rgba", (guint) color_map[cZeroLine]);
998                 manage_zero_line ();
999         }
1000 }
1001
1002 void
1003 AudioRegionView::create_one_wave (uint32_t which, bool direct)
1004 {
1005         AudioTimeAxisView& atv (*(dynamic_cast<AudioTimeAxisView*>(&trackview))); // ick
1006         uint32_t nchans = atv.get_diskstream()->n_channels();
1007         uint32_t n;
1008         uint32_t nwaves = std::min (nchans, region.n_channels());
1009         
1010         gdouble ht;
1011         if (trackview.height < NAME_HIGHLIGHT_SIZE) {
1012                 ht = ((trackview.height) / (double) nchans);
1013         } else {
1014                 ht = ((trackview.height - NAME_HIGHLIGHT_SIZE) / (double) nchans);
1015         }
1016         gdouble yoff = which * ht;
1017
1018         WaveView *wave = new WaveView(*group);
1019
1020         wave->property_data_src().set_value( (gpointer) &region);
1021         wave->property_cache().set_value( wave_caches[which]);
1022         wave->property_cache_updater().set_value( (gboolean) true);
1023         wave->property_channel().set_value( (guint32) which);
1024         wave->property_length_function().set_value( (gpointer) region_length_from_c);
1025         wave->property_sourcefile_length_function().set_value((gpointer) sourcefile_length_from_c);
1026         wave->property_peak_function().set_value( (gpointer) region_read_peaks_from_c);
1027         wave->property_x().set_value( 0.0);
1028         wave->property_y().set_value( yoff);
1029         wave->property_height().set_value( (double) ht);
1030         wave->property_samples_per_unit().set_value( samples_per_unit);
1031         wave->property_amplitude_above_axis().set_value( _amplitude_above_axis);
1032         wave->property_wave_color().set_value(region.muted() ? color_map[cMutedWaveForm] : color_map[cWaveForm]);
1033         wave->property_region_start().set_value(region.start());
1034 //      WaveView *wave = gnome_canvas_item_new (GNOME_CANVAS_GROUP(group),
1035 //                                                 gnome_canvas_waveview_get_type (),
1036 //                                                 "data_src", (gpointer) &region,
1037 //                                                 "cache", wave_caches[which],
1038 //                                                 "cache_updater", (gboolean) true,
1039 //                                                 "channel", (guint32) which,
1040 //                                                 "length_function", (gpointer) region_length_from_c,
1041 //                                                 "sourcefile_length_function",(gpointer) sourcefile_length_from_c,
1042 //                                                 "peak_function", (gpointer) region_read_peaks_from_c,
1043 //                                                 "x", 0.0,
1044 //                                                 "y", yoff,
1045 //                                                 "height", (double) ht,
1046 //                                                 "samples_per_unit", samples_per_unit,
1047 //                                                 "amplitude_above_axis", _amplitude_above_axis,
1048 //                                                 "wave_color", (guint32) (region.muted() ? color_map[cMutedWaveForm] : color_map[cWaveForm]),
1049 //                                                 "region_start",(guint32) region.start(),
1050 //                                                 NULL);
1051         
1052         if (!(_flags & WaveformVisible)) {
1053                 wave->hide();
1054         }
1055
1056         /* note: calling this function is serialized by the lock
1057            held in the peak building thread that signals that
1058            peaks are ready for use *or* by the fact that it is
1059            called one by one from the GUI thread.
1060         */
1061
1062         if (which < nchans) {
1063                 tmp_waves[which] = (wave);
1064         } else {
1065                 /* n-channel track, >n-channel source */
1066         }
1067         
1068         /* see if we're all ready */
1069         
1070         for (n = 0; n < nchans; ++n) {
1071                 if (tmp_waves[n] == 0) {
1072                         break;
1073                 }
1074         }
1075         
1076         if (n == nwaves) {
1077                 /* all waves are ready */
1078                 tmp_waves.resize(nwaves);
1079                 waves = tmp_waves;
1080                 tmp_waves.clear ();
1081                 
1082                 if (!zero_line) {
1083                         zero_line = new ArdourCanvas::Line (*group);
1084                         zero_line->set_property ("x1", (gdouble) 1.0);
1085                         zero_line->set_property ("x2", (gdouble) (region.length() / samples_per_unit) - 1.0);
1086                         zero_line->set_property ("color_rgba", (guint) color_map[cZeroLine]);
1087                         manage_zero_line ();
1088                 }
1089         }
1090 }
1091
1092 void
1093 AudioRegionView::peaks_ready_handler (uint32_t which)
1094 {
1095         Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun(*this, &AudioRegionView::create_one_wave), which, false));
1096 }
1097
1098 void
1099 AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
1100 {
1101         double x, y;
1102
1103         /* don't create points that can't be seen */
1104
1105         set_envelope_visible (true);
1106         
1107         x = ev->button.x;
1108         y = ev->button.y;
1109
1110         item->w2i (x, y);
1111
1112         jack_nframes_t fx = trackview.editor.pixel_to_frame (x);
1113
1114         if (fx > region.length()) {
1115                 return;
1116         }
1117
1118         /* compute vertical fractional position */
1119
1120         y = 1.0 - (y / (trackview.height - NAME_HIGHLIGHT_SIZE));
1121         
1122         /* map using gain line */
1123
1124         gain_line->view_to_model_y (y);
1125
1126         trackview.session().begin_reversible_command (_("add gain control point"));
1127         trackview.session().add_undo (region.envelope().get_memento());
1128
1129
1130         if (!region.envelope_active()) {
1131                 trackview.session().add_undo( bind( mem_fun(region, &AudioRegion::set_envelope_active), false) );
1132                 region.set_envelope_active(true);
1133                 trackview.session().add_redo( bind( mem_fun(region, &AudioRegion::set_envelope_active), true) );
1134         }
1135
1136         region.envelope().add (fx, y);
1137         
1138         trackview.session().add_redo_no_execute (region.envelope().get_memento());
1139         trackview.session().commit_reversible_command ();
1140 }
1141
1142 void
1143 AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev)
1144 {
1145         ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
1146         region.envelope().erase (cp->model);
1147 }
1148
1149 void
1150 AudioRegionView::store_flags()
1151 {
1152         XMLNode *node = new XMLNode ("GUI");
1153
1154         node->add_property ("waveform-visible", (_flags & WaveformVisible) ? "yes" : "no");
1155         node->add_property ("envelope-visible", (_flags & EnvelopeVisible) ? "yes" : "no");
1156
1157         region.add_extra_xml (*node);
1158 }
1159
1160 void
1161 AudioRegionView::set_flags (XMLNode* node)
1162 {
1163         XMLProperty *prop;
1164
1165         if ((prop = node->property ("waveform-visible")) != 0) {
1166                 if (prop->value() == "yes") {
1167                         _flags |= WaveformVisible;
1168                 }
1169         }
1170
1171         if ((prop = node->property ("envelope-visible")) != 0) {
1172                 if (prop->value() == "yes") {
1173                         _flags |= EnvelopeVisible;
1174                 }
1175         }
1176 }
1177         
1178 void
1179 AudioRegionView::set_waveform_shape (WaveformShape shape)
1180 {
1181         bool yn;
1182
1183         /* this slightly odd approach is to leave the door open to 
1184            other "shapes" such as spectral displays, etc.
1185         */
1186
1187         switch (shape) {
1188         case Rectified:
1189                 yn = true;
1190                 break;
1191
1192         default:
1193                 yn = false;
1194                 break;
1195         }
1196
1197         if (yn != (bool) (_flags & WaveformRectified)) {
1198                 for (vector<WaveView *>::iterator wave = waves.begin(); wave != waves.end() ; ++wave) {
1199                         (*wave)->property_rectified().set_value(yn);
1200                 }
1201
1202                 if (zero_line) {
1203                         if (yn) {
1204                                 zero_line->hide();
1205                         } else {
1206                                 zero_line->show();
1207                         }
1208                 }
1209
1210                 if (yn) {
1211                         _flags |= WaveformRectified;
1212                 } else {
1213                         _flags &= ~WaveformRectified;
1214                 }
1215         }
1216 }
1217
1218 std::string
1219 AudioRegionView::get_item_name ()
1220 {
1221         return region.name();
1222 }
1223
1224 void
1225 AudioRegionView::move (double x_delta, double y_delta)
1226 {
1227         if (region.locked() || (x_delta == 0 && y_delta == 0)) {
1228                 return;
1229         }
1230
1231         get_canvas_group()->move (x_delta, y_delta);
1232
1233         /* note: ghosts never leave their tracks so y_delta for them is always zero */
1234
1235         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1236                 (*i)->group->move (x_delta, 0.0);
1237         }
1238 }
1239
1240 GhostRegion*
1241 AudioRegionView::add_ghost (AutomationTimeAxisView& atv)
1242 {
1243         AudioTimeAxisView& myatv (*(dynamic_cast<AudioTimeAxisView*>(&trackview))); // ick
1244         double unit_position = region.position () / samples_per_unit;
1245         GhostRegion* ghost = new GhostRegion (atv, unit_position);
1246         uint32_t nchans;
1247         
1248         nchans = myatv.get_diskstream()->n_channels();
1249
1250         for (uint32_t n = 0; n < nchans; ++n) {
1251                 
1252                 if (n >= region.n_channels()) {
1253                         break;
1254                 }
1255                 
1256                 WaveView *wave = new WaveView(*ghost->group);
1257
1258                 wave->property_data_src().set_value( &region);
1259                 wave->property_cache().set_value( wave_caches[n]);
1260                 wave->property_cache_updater().set_value(false);
1261                 wave->property_channel().set_value(n);
1262                 wave->property_length_function().set_value((gpointer)region_length_from_c);
1263                 wave->property_sourcefile_length_function().set_value((gpointer) sourcefile_length_from_c);
1264                 wave->property_peak_function().set_value( (gpointer) region_read_peaks_from_c);
1265                 wave->property_x().set_value( 0.0);
1266                 wave->property_samples_per_unit().set_value( samples_per_unit);
1267                 wave->property_amplitude_above_axis().set_value( _amplitude_above_axis);
1268                 wave->property_wave_color().set_value(color_map[cGhostTrackWave]);
1269                 wave->property_region_start().set_value(region.start());
1270                 //              WaveView *wave = gnome_canvas_item_new (GNOME_CANVAS_GROUP(ghost->group),
1271                 //                                                         gnome_canvas_waveview_get_type (),
1272                 //                                                         "data_src", (gpointer) &region,
1273                 //                                                         "cache", wave_caches[n],
1274                 //                                                         "cache_updater", (gboolean) false,
1275                 //                                                         "channel", (guint32) n,
1276                 //                                                         "length_function", (gpointer) region_length_from_c,
1277                 //                                                         "sourcefile_length_function",(gpointer) sourcefile_length_from_c,
1278                 //                                                         "peak_function", (gpointer) region_read_peaks_from_c,
1279                 //                                                         "x", 0.0,
1280                 //                                                         "samples_per_unit", samples_per_unit,
1281                 //                                                         "amplitude_above_axis", _amplitude_above_axis,
1282                 //                                                         "wave_color", color_map[cGhostTrackWave],
1283                 //                                                         "region_start", (guint32) region.start(),
1284                 //                                                         NULL);
1285
1286                 
1287                 ghost->waves.push_back(wave);
1288         }
1289
1290         ghost->set_height ();
1291         ghost->set_duration (region.length() / samples_per_unit);
1292         ghosts.push_back (ghost);
1293
1294         ghost->GoingAway.connect (mem_fun(*this, &AudioRegionView::remove_ghost));
1295
1296         return ghost;
1297 }
1298
1299 void
1300 AudioRegionView::remove_ghost (GhostRegion* ghost)
1301 {
1302         if (in_destructor) {
1303                 return;
1304         }
1305
1306         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1307                 if (*i == ghost) {
1308                         ghosts.erase (i);
1309                         break;
1310                 }
1311         }
1312 }
1313
1314 uint32_t
1315 AudioRegionView::get_fill_color ()
1316 {
1317         return fill_color;
1318 }
1319
1320 void
1321 AudioRegionView::entered ()
1322 {
1323         if (_flags & EnvelopeVisible) {
1324                 gain_line->show_all_control_points ();
1325         }
1326
1327         uint32_t r,g,b,a;
1328         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
1329         a=255;
1330         
1331         fade_in_handle->set_property ("fill_color_rgba", RGBA_TO_UINT(r,g,b,a));
1332         fade_out_handle->set_property ("fill_color_rgba", RGBA_TO_UINT(r,g,b,a));
1333 }
1334
1335 void
1336 AudioRegionView::exited ()
1337 {
1338         gain_line->hide_all_but_selected_control_points ();
1339         
1340         uint32_t r,g,b,a;
1341         UINT_TO_RGBA(fade_color,&r,&g,&b,&a);
1342         a=0;
1343         
1344         fade_in_handle->set_property ("fill_color_rgba", RGBA_TO_UINT(r,g,b,a));
1345         fade_out_handle->set_property ("fill_color_rgba", RGBA_TO_UINT(r,g,b,a));
1346 }
1347
1348 void
1349 AudioRegionView::envelope_active_changed ()
1350 {
1351         gain_line->set_line_color (region.envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]);
1352 }
1353
1354 void
1355 AudioRegionView::set_waveview_data_src()
1356 {
1357
1358         double unit_length= region.length() / samples_per_unit;
1359
1360         for (uint32_t n = 0; n < waves.size(); ++n) {
1361                 // TODO: something else to let it know the channel
1362                 waves[n]->property_data_src().set_value(&region);
1363         }
1364         
1365         for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1366                 
1367                 (*i)->set_duration (unit_length);
1368                 
1369                 for (vector<WaveView*>::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) {
1370                         (*w)->property_data_src().set_value(&region);
1371                 }
1372         }
1373
1374 }
1375
1376