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