e074e7626c87933fa39d1fad85a4b7c096084635
[ardour.git] / gtk2_ardour / crossfade_view.cc
1 /*
2     Copyright (C) 2003 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 <algorithm>
22
23 #include <ardour/region.h>
24 #include <gtkmmext/doi.h>
25
26 #include "canvas-simplerect.h"
27 #include "canvas-curve.h"
28 #include "crossfade_view.h"
29 #include "rgb_macros.h"
30 #include "audio_time_axis.h"
31 #include "public_editor.h"
32 #include "regionview.h"
33 #include "utils.h"
34
35 using namespace SigC;
36 using namespace ARDOUR;
37 using namespace Editing;
38
39 SigC::Signal1<void,CrossfadeView*> CrossfadeView::GoingAway;
40
41 CrossfadeView::CrossfadeView (GtkCanvasGroup *parent, 
42                               AudioTimeAxisView &tv, 
43                               Crossfade& xf, 
44                               double spu,
45                               GdkColor& basic_color,
46                               AudioRegionView& lview,
47                               AudioRegionView& rview)
48                               
49
50         : TimeAxisViewItem ("xf.name()", parent, tv, spu, basic_color, xf.position(), 
51                             xf.overlap_length(), TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowFrame)),
52           crossfade (xf),
53           left_view (lview),
54           right_view (rview)
55         
56 {
57         _valid = true;
58         _visible = true;
59
60         fade_in = gtk_canvas_item_new (GTK_CANVAS_GROUP(group),
61                                        gtk_canvas_line_get_type(),
62                                        "fill_color_rgba", color_map[cCrossfadeLine],
63                                         "width_pixels", (guint) 1,
64                                        NULL);
65
66         fade_out = gtk_canvas_item_new (GTK_CANVAS_GROUP(group),
67                                         gtk_canvas_line_get_type(),
68                                         "fill_color_rgba", color_map[cCrossfadeLine],
69                                         "width_pixels", (guint) 1,
70                                         NULL);
71         
72         set_height (get_time_axis_view().height);
73
74         /* no frame around the xfade or overlap rects */
75
76         gtk_canvas_item_set (frame, "outline_what", 0, NULL);
77
78         /* never show the vestigial frame */
79
80         gtk_canvas_item_hide (vestigial_frame);
81         show_vestigial = false;
82
83         gtk_object_set_data (GTK_OBJECT(group), "crossfadeview", this);
84         gtk_signal_connect (GTK_OBJECT(group), "event",
85                             (GtkSignalFunc) PublicEditor::canvas_crossfade_view_event,
86                             this);
87
88         crossfade_changed (Change (~0));
89
90         crossfade.StateChanged.connect (slot (*this, &CrossfadeView::crossfade_changed));
91 }
92
93 CrossfadeView::~CrossfadeView ()
94 {
95          GoingAway (this) ; /* EMIT_SIGNAL */
96 }
97
98 std::string
99 CrossfadeView::get_item_name ()
100 {
101         return "xfade";
102 //      return crossfade.name();
103 }
104
105 void
106 CrossfadeView::reset_width_dependent_items (double pixel_width)
107 {
108         TimeAxisViewItem::reset_width_dependent_items (pixel_width);
109
110         active_changed ();
111
112         if (pixel_width < 5) {
113                 gtk_canvas_item_hide (fade_in);
114                 gtk_canvas_item_hide (fade_out);
115         }
116 }
117
118 void
119 CrossfadeView::set_height (double height)
120 {
121         if (height == TimeAxisView::Smaller ||
122                 height == TimeAxisView::Small)
123                 TimeAxisViewItem::set_height (height - 3 );
124         else
125                 TimeAxisViewItem::set_height (height - NAME_HIGHLIGHT_SIZE - 3 );
126
127         redraw_curves ();
128 }
129
130 void
131 CrossfadeView::crossfade_changed (Change what_changed)
132 {
133         bool need_redraw_curves = false;
134
135         if (what_changed & BoundsChanged) {
136                 set_position (crossfade.position(), this);
137                 set_duration (crossfade.overlap_length(), this);
138                 need_redraw_curves = true;
139         }
140         
141         if (what_changed & Crossfade::ActiveChanged) {
142                 /* calls redraw_curves */
143                 active_changed ();
144         } else if (need_redraw_curves) {
145                 redraw_curves ();
146         }
147 }
148
149 void
150 CrossfadeView::redraw_curves ()
151 {
152         GtkCanvasPoints* points; 
153         int32_t npoints;
154         float* vec;
155         
156         double h;
157
158         /*
159          At "height - 3.0" the bottom of the crossfade touches the name highlight or the bottom of the track (if the
160          track is either Small or Smaller.
161          */
162         switch(get_time_axis_view().height) {
163                 case TimeAxisView::Smaller:
164                 case TimeAxisView::Small:
165                         h = get_time_axis_view().height - 3.0;
166                         break;
167
168                 default:
169                         h = get_time_axis_view().height - NAME_HIGHLIGHT_SIZE - 3.0;
170         }
171
172         if (h < 0) {
173                 /* no space allocated yet */
174                 return;
175         }
176
177         npoints = get_time_axis_view().editor.frame_to_pixel (crossfade.length());
178         npoints = std::min (gdk_screen_width(), npoints);
179
180         if (!_visible || !crossfade.active() || npoints < 3) {
181                 gtk_canvas_item_hide (fade_in);
182                 gtk_canvas_item_hide (fade_out);
183                 return;
184         } else {
185                 gtk_canvas_item_show (fade_in);
186                 gtk_canvas_item_show (fade_out);
187         } 
188
189         points = get_canvas_points ("xfade edit redraw", npoints);
190         vec = new float[npoints];
191
192         crossfade.fade_in().get_vector (0, crossfade.length(), vec, npoints);
193         for (int i = 0, pci = 0; i < npoints; ++i) {
194                 points->coords[pci++] = i;
195                 points->coords[pci++] = 2.0 + h - (h * vec[i]);
196         }
197         gtk_canvas_item_set (fade_in, "points", points, NULL);
198
199         crossfade.fade_out().get_vector (0, crossfade.length(), vec, npoints);
200         for (int i = 0, pci = 0; i < npoints; ++i) {
201                 points->coords[pci++] = i;
202                 points->coords[pci++] = 2.0 + h - (h * vec[i]);
203         }
204         gtk_canvas_item_set (fade_out, "points", points, NULL);
205
206         delete [] vec;
207
208         gtk_canvas_points_unref (points);
209
210         /* XXX this is ugly, but it will have to wait till Crossfades are reimplented
211            as regions. This puts crossfade views on top of a track, above all regions.
212         */
213
214         gtk_canvas_item_raise_to_top (group);
215 }
216
217 void
218 CrossfadeView::active_changed ()
219 {
220         if (crossfade.active()) {
221                 gtk_canvas_item_set (frame, "fill_color_rgba", color_map[cActiveCrossfade], NULL);
222         } else {
223                 gtk_canvas_item_set (frame, "fill_color_rgba", color_map[cInactiveCrossfade], NULL);
224         }
225
226         redraw_curves ();
227 }
228
229 void
230 CrossfadeView::set_valid (bool yn)
231 {
232         _valid = yn;
233 }
234
235 AudioRegionView&
236 CrossfadeView::upper_regionview () const
237 {
238         if (left_view.region.layer() > right_view.region.layer()) {
239                 return left_view;
240         } else {
241                 return right_view;
242         }
243 }
244
245 void
246 CrossfadeView::show ()
247 {
248         gtk_canvas_item_show (group);
249         _visible = true;
250 }
251
252 void
253 CrossfadeView::hide ()
254 {
255         gtk_canvas_item_hide (group);
256         _visible = false;
257 }
258
259 void
260 CrossfadeView::fake_hide ()
261 {
262         gtk_canvas_item_hide (group);
263 }