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 "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"
34 #include "canvas_impl.h"
35 #include "ardour_ui.h"
37 using namespace ARDOUR;
39 using namespace Editing;
40 using namespace Gnome;
41 using namespace Canvas;
43 PBD::Signal1<void,CrossfadeView*> CrossfadeView::CatchDeletion;
45 CrossfadeView::CrossfadeView (ArdourCanvas::Group *parent,
46 RouteTimeAxisView &tv,
47 boost::shared_ptr<Crossfade> xf,
49 Gdk::Color& basic_color,
50 AudioRegionView& lview,
51 AudioRegionView& rview)
54 : TimeAxisViewItem ("xfade" /*xf.name()*/, *parent, tv, spu, basic_color, xf->position(),
55 xf->length(), false, false, TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowFrame)),
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;
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;
72 /* no frame around the xfade or overlap rects */
74 frame->property_outline_what() = 0;
76 /* never show the vestigial frame */
77 vestigial_frame->hide();
78 show_vestigial = false;
80 group->signal_event().connect (sigc::bind (sigc::mem_fun (tv.editor(), &PublicEditor::canvas_crossfade_view_event), group, this));
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);
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));
92 CrossfadeView::~CrossfadeView ()
94 CatchDeletion (this) ; /* EMIT_SIGNAL */
98 CrossfadeView::reset_width_dependent_items (double pixel_width)
100 TimeAxisViewItem::reset_width_dependent_items (pixel_width);
104 if (pixel_width < 5) {
111 CrossfadeView::set_height (double h)
113 if (h > TimeAxisView::preset_height (HeightSmall)) {
114 h -= NAME_HIGHLIGHT_SIZE;
117 TimeAxisViewItem::set_height (h);
123 CrossfadeView::crossfade_changed (const PropertyChange& what_changed)
125 bool need_redraw_curves = false;
127 if (what_changed.contains (ARDOUR::bounds_change)) {
128 set_position (crossfade->position(), this);
129 set_duration (crossfade->length(), this);
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;
136 if (what_changed.contains (ARDOUR::Properties::follow_overlap)) {
137 need_redraw_curves = true;
140 if (what_changed.contains (ARDOUR::Properties::active)) {
141 /* calls redraw_curves */
143 } else if (need_redraw_curves) {
148 /** Set up our fade_in and fade_out curves to contain points for the currently visible portion
152 CrossfadeView::redraw_curves ()
154 if (!crossfade->following_overlap()) {
155 /* curves should not be visible */
162 /* no space allocated yet */
166 PublicEditor& editor = get_time_axis_view().editor ();
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 ();
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);
177 _all_in_view = (editor_left <= xfade_left && editor_right >= xfade_right);
179 /* Hence the number of points that we will render */
180 int32_t const npoints = editor.frame_to_pixel (max_frames - min_frames);
182 if (!_visible || !crossfade->active() || npoints < 3) {
191 Points* points = get_canvas_points ("xfade edit redraw", npoints);
192 float* vec = new float[npoints];
194 crossfade->fade_in().curve().get_vector (min_frames - crossfade->position(), max_frames - crossfade->position(), vec, npoints);
196 /* Work out the offset from the start of the crossfade to the visible part, in pixels */
198 if (crossfade->position() < editor.leftmost_position()) {
199 xoff = editor.frame_to_pixel (min_frames) - editor.frame_to_pixel (crossfade->position ());
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]));
208 fade_in->property_points() = *points;
210 crossfade->fade_out().curve().get_vector (min_frames - crossfade->position(), max_frames - crossfade->position(), vec, npoints);
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]));
218 fade_out->property_points() = *points;
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.
228 group->raise_to_top();
232 CrossfadeView::active_changed ()
234 if (crossfade->active()) {
235 frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ActiveCrossfade.get();
237 frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_InactiveCrossfade.get();
244 CrossfadeView::color_handler ()
250 CrossfadeView::set_valid (bool yn)
256 CrossfadeView::upper_regionview () const
258 if (left_view.region()->layer() > right_view.region()->layer()) {
266 CrossfadeView::show ()
274 CrossfadeView::hide ()
281 CrossfadeView::fake_hide ()
287 CrossfadeView::crossfade_fades_changed ()
293 CrossfadeView::horizontal_position_changed ()
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'