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)),
66 fade_in = new Line (*group);
67 fade_in->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeLine.get();
68 fade_in->property_width_pixels() = 1;
70 fade_out = new Line (*group);
71 fade_out->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeLine.get();
72 fade_out->property_width_pixels() = 1;
74 /* no frame around the xfade or overlap rects */
76 frame->property_outline_what() = 0;
78 /* never show the vestigial frame */
79 vestigial_frame->hide();
80 show_vestigial = false;
82 group->signal_event().connect (sigc::bind (sigc::mem_fun (tv.editor(), &PublicEditor::canvas_crossfade_view_event), group, this));
84 PropertyChange all_crossfade_properties;
85 all_crossfade_properties.add (ARDOUR::Properties::active);
86 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
87 crossfade_changed (all_crossfade_properties);
89 crossfade->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&CrossfadeView::crossfade_changed, this, _1), gui_context());
90 crossfade->FadesChanged.connect (*this, invalidator (*this), ui_bind (&CrossfadeView::crossfade_fades_changed, this), gui_context());
91 ColorsChanged.connect (sigc::mem_fun (*this, &CrossfadeView::color_handler));
94 CrossfadeView::~CrossfadeView ()
96 CatchDeletion (this) ; /* EMIT_SIGNAL */
100 CrossfadeView::reset_width_dependent_items (double pixel_width)
102 TimeAxisViewItem::reset_width_dependent_items (pixel_width);
106 if (pixel_width < 5) {
113 CrossfadeView::set_heights (double fade_height, double child_height)
115 if (child_height > TimeAxisViewItem::NAME_HIGHLIGHT_THRESH) {
116 fade_height -= NAME_HIGHLIGHT_SIZE;
117 child_height -= NAME_HIGHLIGHT_SIZE;
120 TimeAxisViewItem::set_height (fade_height);
121 _child_height = child_height;
127 CrossfadeView::crossfade_changed (const PropertyChange& what_changed)
129 bool need_redraw_curves = false;
131 if (what_changed.contains (ARDOUR::bounds_change)) {
132 set_position (crossfade->position(), this);
133 set_duration (crossfade->length(), this);
135 /* set_duration will call reset_width_dependent_items which in turn will call redraw_curves via active_changed,
136 so no need for us to call it */
137 need_redraw_curves = false;
140 if (what_changed.contains (ARDOUR::Properties::follow_overlap)) {
141 need_redraw_curves = true;
144 if (what_changed.contains (ARDOUR::Properties::active)) {
145 /* calls redraw_curves */
147 } else if (need_redraw_curves) {
152 /** Set up our fade_in and fade_out curves to contain points for the currently visible portion
156 CrossfadeView::redraw_curves ()
158 if (!crossfade->following_overlap()) {
159 /* curves should not be visible */
166 /* no space allocated yet */
170 PublicEditor& editor = get_time_axis_view().editor ();
172 framepos_t const editor_left = editor.leftmost_position ();
173 framepos_t const editor_right = editor_left + editor.current_page_frames ();
174 framepos_t const xfade_left = crossfade->position ();
175 framepos_t const xfade_right = xfade_left + crossfade->length ();
177 /* Work out the range of our frames that are visible */
178 framepos_t const min_frames = std::max (editor_left, xfade_left);
179 framepos_t const max_frames = std::min (editor_right, xfade_right);
181 _all_in_view = (editor_left <= xfade_left && editor_right >= xfade_right);
183 /* Hence the number of points that we will render */
184 int32_t const npoints = editor.frame_to_pixel (max_frames - min_frames);
186 if (!_visible || !crossfade->active() || npoints < 3) {
195 Points* points = get_canvas_points ("xfade edit redraw", npoints);
196 float* vec = new float[npoints];
198 crossfade->fade_in().curve().get_vector (min_frames - crossfade->position(), max_frames - crossfade->position(), vec, npoints);
200 /* Work out the offset from the start of the crossfade to the visible part, in pixels */
202 if (crossfade->position() < editor.leftmost_position()) {
203 xoff = editor.frame_to_pixel (min_frames) - editor.frame_to_pixel (crossfade->position ());
206 for (int i = 0, pci = 0; i < npoints; ++i) {
207 Art::Point &p = (*points)[pci++];
208 p.set_x (xoff + i + 1);
210 double const ho = crossfade->in()->layer() > crossfade->out()->layer() ? _child_height : _height;
211 p.set_y (ho - ((_child_height - 2) * vec[i]));
214 fade_in->property_points() = *points;
216 crossfade->fade_out().curve().get_vector (min_frames - crossfade->position(), max_frames - crossfade->position(), vec, npoints);
218 for (int i = 0, pci = 0; i < npoints; ++i) {
219 Art::Point &p = (*points)[pci++];
220 p.set_x (xoff + i + 1);
222 double const ho = crossfade->in()->layer() < crossfade->out()->layer() ? _child_height : _height;
223 p.set_y (ho - ((_child_height - 2) * vec[i]));
226 fade_out->property_points() = *points;
232 /* XXX this is ugly, but it will have to wait till Crossfades are reimplented
233 as regions. This puts crossfade views on top of a track, above all regions.
236 group->raise_to_top();
240 CrossfadeView::active_changed ()
242 if (crossfade->active()) {
243 frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ActiveCrossfade.get();
245 frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_InactiveCrossfade.get();
252 CrossfadeView::color_handler ()
258 CrossfadeView::set_valid (bool yn)
264 CrossfadeView::show ()
272 CrossfadeView::hide ()
279 CrossfadeView::fake_hide ()
285 CrossfadeView::crossfade_fades_changed ()
291 CrossfadeView::horizontal_position_changed ()
293 /* If the crossfade curves are entirely within the editor's visible space, there is
294 no need to redraw them here as they will be completely drawn (as distinct from
295 the other case where the horizontal position change will uncover `undrawn'