2 Copyright (C) 2003 Paul Davis
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.
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.
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.
22 #include "ardour/region.h"
23 #include <gtkmm2ext/doi.h>
25 #include "canvas-simplerect.h"
26 #include "canvas-curve.h"
27 #include "crossfade_view.h"
28 #include "global_signals.h"
29 #include "gui_thread.h"
30 #include "rgb_macros.h"
31 #include "audio_time_axis.h"
32 #include "public_editor.h"
33 #include "audio_region_view.h"
35 #include "canvas_impl.h"
36 #include "ardour_ui.h"
38 using namespace ARDOUR
;
40 using namespace Editing
;
41 using namespace Gnome
;
42 using namespace Canvas
;
44 PBD::Signal1
<void,CrossfadeView
*> CrossfadeView::CatchDeletion
;
46 CrossfadeView::CrossfadeView (ArdourCanvas::Group
*parent
,
47 RouteTimeAxisView
&tv
,
48 boost::shared_ptr
<Crossfade
> xf
,
50 Gdk::Color
& basic_color
,
51 AudioRegionView
& lview
,
52 AudioRegionView
& rview
)
55 : TimeAxisViewItem ("xfade" /*xf.name()*/, *parent
, tv
, spu
, basic_color
, xf
->position(),
56 xf
->length(), false, false, TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowFrame
)),
65 fade_in
= new Line (*group
);
66 fade_in
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeLine
.get();
67 fade_in
->property_width_pixels() = 1;
69 fade_out
= new Line (*group
);
70 fade_out
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeLine
.get();
71 fade_out
->property_width_pixels() = 1;
73 /* no frame around the xfade or overlap rects */
75 frame
->property_outline_what() = 0;
77 /* never show the vestigial frame */
78 vestigial_frame
->hide();
79 show_vestigial
= false;
81 group
->signal_event().connect (sigc::bind (sigc::mem_fun (tv
.editor(), &PublicEditor::canvas_crossfade_view_event
), group
, this));
83 PropertyChange all_crossfade_properties
;
84 all_crossfade_properties
.add (ARDOUR::Properties::active
);
85 all_crossfade_properties
.add (ARDOUR::Properties::follow_overlap
);
86 crossfade_changed (all_crossfade_properties
);
88 crossfade
->PropertyChanged
.connect (*this, invalidator (*this), ui_bind (&CrossfadeView::crossfade_changed
, this, _1
), gui_context());
89 crossfade
->FadesChanged
.connect (*this, invalidator (*this), ui_bind (&CrossfadeView::crossfade_fades_changed
, this), gui_context());
90 ColorsChanged
.connect (sigc::mem_fun (*this, &CrossfadeView::color_handler
));
93 CrossfadeView::~CrossfadeView ()
95 CatchDeletion (this) ; /* EMIT_SIGNAL */
99 CrossfadeView::reset_width_dependent_items (double pixel_width
)
101 TimeAxisViewItem::reset_width_dependent_items (pixel_width
);
105 if (pixel_width
< 5) {
112 CrossfadeView::set_height (double h
)
114 if (h
> TimeAxisView::preset_height (HeightSmall
)) {
115 h
-= NAME_HIGHLIGHT_SIZE
;
118 TimeAxisViewItem::set_height (h
);
124 CrossfadeView::crossfade_changed (const PropertyChange
& what_changed
)
126 bool need_redraw_curves
= false;
128 if (what_changed
.contains (ARDOUR::bounds_change
)) {
129 set_position (crossfade
->position(), this);
130 set_duration (crossfade
->length(), this);
132 /* set_duration will call reset_width_dependent_items which in turn will call redraw_curves via active_changed,
133 so no need for us to call it */
134 need_redraw_curves
= false;
137 if (what_changed
.contains (ARDOUR::Properties::follow_overlap
)) {
138 need_redraw_curves
= true;
141 if (what_changed
.contains (ARDOUR::Properties::active
)) {
142 /* calls redraw_curves */
144 } else if (need_redraw_curves
) {
149 /** Set up our fade_in and fade_out curves to contain points for the currently visible portion
153 CrossfadeView::redraw_curves ()
155 if (!crossfade
->following_overlap()) {
156 /* curves should not be visible */
163 /* no space allocated yet */
167 PublicEditor
& editor
= get_time_axis_view().editor ();
169 framepos_t
const editor_left
= editor
.leftmost_position ();
170 framepos_t
const editor_right
= editor_left
+ editor
.current_page_frames ();
171 framepos_t
const xfade_left
= crossfade
->position ();
172 framepos_t
const xfade_right
= xfade_left
+ crossfade
->length ();
174 /* Work out the range of our frames that are visible */
175 framepos_t
const min_frames
= std::max (editor_left
, xfade_left
);
176 framepos_t
const max_frames
= std::min (editor_right
, xfade_right
);
178 _all_in_view
= (editor_left
<= xfade_left
&& editor_right
>= xfade_right
);
180 /* Hence the number of points that we will render */
181 int32_t const npoints
= editor
.frame_to_pixel (max_frames
- min_frames
);
183 if (!_visible
|| !crossfade
->active() || npoints
< 3) {
192 Points
* points
= get_canvas_points ("xfade edit redraw", npoints
);
193 float* vec
= new float[npoints
];
195 crossfade
->fade_in().curve().get_vector (min_frames
- crossfade
->position(), max_frames
- crossfade
->position(), vec
, npoints
);
197 /* Work out the offset from the start of the crossfade to the visible part, in pixels */
199 if (crossfade
->position() < editor
.leftmost_position()) {
200 xoff
= editor
.frame_to_pixel (min_frames
) - editor
.frame_to_pixel (crossfade
->position ());
203 for (int i
= 0, pci
= 0; i
< npoints
; ++i
) {
204 Art::Point
&p
= (*points
)[pci
++];
205 p
.set_x (xoff
+ i
+ 1);
206 p
.set_y (_height
- ((_height
- 2) * vec
[i
]));
209 fade_in
->property_points() = *points
;
211 crossfade
->fade_out().curve().get_vector (min_frames
- crossfade
->position(), max_frames
- crossfade
->position(), vec
, npoints
);
213 for (int i
= 0, pci
= 0; i
< npoints
; ++i
) {
214 Art::Point
&p
= (*points
)[pci
++];
215 p
.set_x (xoff
+ i
+ 1);
216 p
.set_y (_height
- ((_height
- 2) * vec
[i
]));
219 fade_out
->property_points() = *points
;
225 /* XXX this is ugly, but it will have to wait till Crossfades are reimplented
226 as regions. This puts crossfade views on top of a track, above all regions.
229 group
->raise_to_top();
233 CrossfadeView::active_changed ()
235 if (crossfade
->active()) {
236 frame
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ActiveCrossfade
.get();
238 frame
->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_InactiveCrossfade
.get();
245 CrossfadeView::color_handler ()
251 CrossfadeView::set_valid (bool yn
)
257 CrossfadeView::upper_regionview () const
259 if (left_view
.region()->layer() > right_view
.region()->layer()) {
267 CrossfadeView::show ()
275 CrossfadeView::hide ()
282 CrossfadeView::fake_hide ()
288 CrossfadeView::crossfade_fades_changed ()
294 CrossfadeView::horizontal_position_changed ()
296 /* If the crossfade curves are entirely within the editor's visible space, there is
297 no need to redraw them here as they will be completely drawn (as distinct from
298 the other case where the horizontal position change will uncover `undrawn'