factor out shuttle controller to its own class, new design
[ardour2.git] / gtk2_ardour / crossfade_view.cc
blob0c420e74ade786fff73cdf22d5ef84f3f71386fb
1 /*
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.
20 #include <algorithm>
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"
34 #include "utils.h"
35 #include "canvas_impl.h"
36 #include "ardour_ui.h"
38 using namespace ARDOUR;
39 using namespace PBD;
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,
49 double spu,
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)),
57 crossfade (xf),
58 left_view (lview),
59 right_view (rview),
60 _all_in_view (false)
62 _valid = true;
63 _visible = true;
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 */
98 void
99 CrossfadeView::reset_width_dependent_items (double pixel_width)
101 TimeAxisViewItem::reset_width_dependent_items (pixel_width);
103 active_changed ();
105 if (pixel_width < 5) {
106 fade_in->hide();
107 fade_out->hide();
111 void
112 CrossfadeView::set_height (double h)
114 if (h > TimeAxisView::preset_height (HeightSmall)) {
115 h -= NAME_HIGHLIGHT_SIZE;
118 TimeAxisViewItem::set_height (h);
120 redraw_curves ();
123 void
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 */
143 active_changed ();
144 } else if (need_redraw_curves) {
145 redraw_curves ();
149 /** Set up our fade_in and fade_out curves to contain points for the currently visible portion
150 * of the crossfade.
152 void
153 CrossfadeView::redraw_curves ()
155 if (!crossfade->following_overlap()) {
156 /* curves should not be visible */
157 fade_in->hide ();
158 fade_out->hide ();
159 return;
162 if (_height < 0) {
163 /* no space allocated yet */
164 return;
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) {
184 fade_in->hide();
185 fade_out->hide();
186 return;
187 } else {
188 fade_in->show();
189 fade_out->show();
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 */
198 double xoff = 0;
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;
221 delete [] vec;
223 delete 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();
232 void
233 CrossfadeView::active_changed ()
235 if (crossfade->active()) {
236 frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ActiveCrossfade.get();
237 } else {
238 frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_InactiveCrossfade.get();
241 redraw_curves ();
244 void
245 CrossfadeView::color_handler ()
247 active_changed ();
250 void
251 CrossfadeView::set_valid (bool yn)
253 _valid = yn;
256 AudioRegionView&
257 CrossfadeView::upper_regionview () const
259 if (left_view.region()->layer() > right_view.region()->layer()) {
260 return left_view;
261 } else {
262 return right_view;
266 void
267 CrossfadeView::show ()
269 _visible = true;
270 group->show();
271 redraw_curves ();
274 void
275 CrossfadeView::hide ()
277 group->hide();
278 _visible = false;
281 void
282 CrossfadeView::fake_hide ()
284 group->hide();
287 void
288 CrossfadeView::crossfade_fades_changed ()
290 redraw_curves ();
293 void
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'
299 sections).
302 if (!_all_in_view) {
303 redraw_curves ();