remove using boost::shared_ptr stuff from session.cc
[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 */
19
20 #include <algorithm>
21
22 #include "ardour/region.h"
23 #include <gtkmm2ext/doi.h>
24
25 #include "canvas-simplerect.h"
26 #include "canvas-curve.h"
27 #include "crossfade_view.h"
28 #include "gui_thread.h"
29 #include "rgb_macros.h"
30 #include "audio_time_axis.h"
31 #include "public_editor.h"
32 #include "audio_region_view.h"
33 #include "utils.h"
34 #include "canvas_impl.h"
35 #include "ardour_ui.h"
36
37 using namespace ARDOUR;
38 using namespace PBD;
39 using namespace Editing;
40 using namespace Gnome;
41 using namespace Canvas;
42
43 PBD::Signal1<void,CrossfadeView*> CrossfadeView::CatchDeletion;
44
45 CrossfadeView::CrossfadeView (ArdourCanvas::Group *parent,
46                               RouteTimeAxisView &tv,
47                               boost::shared_ptr<Crossfade> xf,
48                               double spu,
49                               Gdk::Color& basic_color,
50                               AudioRegionView& lview,
51                               AudioRegionView& rview)
52
53
54         : TimeAxisViewItem ("xfade" /*xf.name()*/, *parent, tv, spu, basic_color, xf->position(),
55                             xf->length(), false, false, TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowFrame)),
56           crossfade (xf),
57           left_view (lview),
58           right_view (rview),
59           _all_in_view (false)
60 {
61         _valid = true;
62         _visible = true;
63
64         fade_in = new Line (*group);
65         fade_in->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeLine.get();
66         fade_in->property_width_pixels() = 1;
67
68         fade_out = new Line (*group);
69         fade_out->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeLine.get();
70         fade_out->property_width_pixels() = 1;
71
72         /* no frame around the xfade or overlap rects */
73
74         frame->property_outline_what() = 0;
75
76         /* never show the vestigial frame */
77         vestigial_frame->hide();
78         show_vestigial = false;
79
80         group->signal_event().connect (sigc::bind (sigc::mem_fun (tv.editor(), &PublicEditor::canvas_crossfade_view_event), group, this));
81
82         PropertyChange all_crossfade_properties;
83         all_crossfade_properties.add (ARDOUR::Properties::active);
84         all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
85         crossfade_changed (all_crossfade_properties);
86
87         crossfade->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&CrossfadeView::crossfade_changed, this, _1), gui_context());
88         crossfade->FadesChanged.connect (*this, invalidator (*this), ui_bind (&CrossfadeView::crossfade_fades_changed, this), gui_context());
89         ColorsChanged.connect (sigc::mem_fun (*this, &CrossfadeView::color_handler));
90 }
91
92 CrossfadeView::~CrossfadeView ()
93 {
94          CatchDeletion (this) ; /* EMIT_SIGNAL */
95 }
96
97 void
98 CrossfadeView::reset_width_dependent_items (double pixel_width)
99 {
100         TimeAxisViewItem::reset_width_dependent_items (pixel_width);
101
102         active_changed ();
103
104         if (pixel_width < 5) {
105                 fade_in->hide();
106                 fade_out->hide();
107         }
108 }
109
110 void
111 CrossfadeView::set_height (double h)
112 {
113         if (h > TimeAxisView::preset_height (HeightSmall)) {
114                 h -= NAME_HIGHLIGHT_SIZE;
115         }
116
117         TimeAxisViewItem::set_height (h);
118
119         redraw_curves ();
120 }
121
122 void
123 CrossfadeView::crossfade_changed (const PropertyChange& what_changed)
124 {
125         bool need_redraw_curves = false;
126
127         if (what_changed.contains (ARDOUR::bounds_change)) {
128                 set_position (crossfade->position(), this);
129                 set_duration (crossfade->length(), this);
130
131                 /* set_duration will call reset_width_dependent_items which in turn will call redraw_curves via active_changed,
132                    so no need for us to call it */
133                 need_redraw_curves = false;
134         }
135
136         if (what_changed.contains (ARDOUR::Properties::follow_overlap)) {
137                 need_redraw_curves = true;
138         }
139
140         if (what_changed.contains (ARDOUR::Properties::active)) {
141                 /* calls redraw_curves */
142                 active_changed ();
143         } else if (need_redraw_curves) {
144                 redraw_curves ();
145         }
146 }
147
148 /** Set up our fade_in and fade_out curves to contain points for the currently visible portion
149  *  of the crossfade.
150  */
151 void
152 CrossfadeView::redraw_curves ()
153 {
154         if (!crossfade->following_overlap()) {
155                 /* curves should not be visible */
156                 fade_in->hide ();
157                 fade_out->hide ();
158                 return;
159         }
160
161         if (_height < 0) {
162                 /* no space allocated yet */
163                 return;
164         }
165
166         PublicEditor& editor = get_time_axis_view().editor ();
167
168         framepos_t const editor_left = editor.leftmost_position ();
169         framepos_t const editor_right = editor_left + editor.current_page_frames ();
170         framepos_t const xfade_left = crossfade->position ();
171         framepos_t const xfade_right = xfade_left + crossfade->length ();
172
173         /* Work out the range of our frames that are visible */
174         framepos_t const min_frames = std::max (editor_left, xfade_left);
175         framepos_t const max_frames = std::min (editor_right, xfade_right);
176
177         _all_in_view = (editor_left <= xfade_left && editor_right >= xfade_right);
178
179         /* Hence the number of points that we will render */
180         int32_t const npoints = editor.frame_to_pixel (max_frames - min_frames);
181         
182         if (!_visible || !crossfade->active() || npoints < 3) {
183                 fade_in->hide();
184                 fade_out->hide();
185                 return;
186         } else {
187                 fade_in->show();
188                 fade_out->show();
189         }
190
191         Points* points = get_canvas_points ("xfade edit redraw", npoints);
192         float* vec = new float[npoints];
193
194         crossfade->fade_in().curve().get_vector (min_frames - crossfade->position(), max_frames - crossfade->position(), vec, npoints);
195
196         /* Work out the offset from the start of the crossfade to the visible part, in pixels */
197         double xoff = 0;
198         if (crossfade->position() < editor.leftmost_position()) {
199                 xoff = editor.frame_to_pixel (min_frames) - editor.frame_to_pixel (crossfade->position ());
200         }
201
202         for (int i = 0, pci = 0; i < npoints; ++i) {
203                 Art::Point &p = (*points)[pci++];
204                 p.set_x (xoff + i + 1);
205                 p.set_y (_height - ((_height - 2) * vec[i]));
206         }
207
208         fade_in->property_points() = *points;
209
210         crossfade->fade_out().curve().get_vector (min_frames - crossfade->position(), max_frames - crossfade->position(), vec, npoints);
211
212         for (int i = 0, pci = 0; i < npoints; ++i) {
213                 Art::Point &p = (*points)[pci++];
214                 p.set_x (xoff + i + 1);
215                 p.set_y (_height - ((_height - 2) * vec[i]));
216         }
217         
218         fade_out->property_points() = *points;
219
220         delete [] vec;
221
222         delete points;
223
224         /* XXX this is ugly, but it will have to wait till Crossfades are reimplented
225            as regions. This puts crossfade views on top of a track, above all regions.
226         */
227
228         group->raise_to_top();
229 }
230
231 void
232 CrossfadeView::active_changed ()
233 {
234         if (crossfade->active()) {
235                 frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ActiveCrossfade.get();
236         } else {
237                 frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_InactiveCrossfade.get();
238         }
239
240         redraw_curves ();
241 }
242
243 void
244 CrossfadeView::color_handler ()
245 {
246         active_changed ();
247 }
248
249 void
250 CrossfadeView::set_valid (bool yn)
251 {
252         _valid = yn;
253 }
254
255 AudioRegionView&
256 CrossfadeView::upper_regionview () const
257 {
258         if (left_view.region()->layer() > right_view.region()->layer()) {
259                 return left_view;
260         } else {
261                 return right_view;
262         }
263 }
264
265 void
266 CrossfadeView::show ()
267 {
268         _visible = true;
269         group->show();
270         redraw_curves ();
271 }
272
273 void
274 CrossfadeView::hide ()
275 {
276         group->hide();
277         _visible = false;
278 }
279
280 void
281 CrossfadeView::fake_hide ()
282 {
283         group->hide();
284 }
285
286 void
287 CrossfadeView::crossfade_fades_changed ()
288 {
289         redraw_curves ();
290 }
291
292 void
293 CrossfadeView::horizontal_position_changed ()
294 {
295         /* If the crossfade curves are entirely within the editor's visible space, there is
296            no need to redraw them here as they will be completely drawn (as distinct from
297            the other case where the horizontal position change will uncover `undrawn'
298            sections).
299         */
300         
301         if (!_all_in_view) {
302                 redraw_curves ();
303         }
304 }