Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.animation;
027
028import javafx.beans.property.ObjectProperty;
029import javafx.beans.property.ObjectPropertyBase;
030import javafx.beans.property.SimpleObjectProperty;
031import javafx.scene.Node;
032import javafx.scene.paint.Color;
033import javafx.scene.shape.Shape;
034import javafx.util.Duration;
035
036/**
037 * This {@code Transition} creates an animation, that changes the filling of a
038 * shape over a {@code duration}. This is done by updating the {@code fill}
039 * variable of the {@code shape} at regular intervals.
040 * <p>
041 * It starts from the {@code fromValue} if provided else uses the {@code shape}
042 * 's {@code fill} value. (The {@code stroke} value has to be a
043 * {@link javafx.scene.paint.Color} in this case).
044 * <p>
045 * It stops at the {@code toValue} value.
046 * 
047 * <p>
048 * Code Segment Example:
049 * </p>
050 * 
051 * <pre>
052 * <code>
053 * import javafx.scene.shape.*;
054 * import javafx.animation.transition.*;
055 * 
056 * ...
057 * 
058 *     Rectangle rect = new Rectangle (100, 40, 100, 100);
059 *     rect.setArcHeight(50);
060 *     rect.setArcWidth(50);
061 * 
062 *     FillTransition ft = new FillTransition(Duration.millis(3000), rect, Color.RED, Color.BLUE);
063 *     ft.setCycleCount(4);
064 *     ft.setAutoReverse(true);
065 * 
066 *     ft.play();
067 * 
068 * ...
069 * 
070 * </code>
071 * </pre>
072 * 
073 * @see Transition
074 * @see Animation
075 * 
076 */
077public final class FillTransition extends Transition {
078
079    private Color start;
080    private Color end;
081
082    /**
083     * The target shape of this {@code FillTransition}.
084     * <p>
085     * It is not possible to change the target {@code shape} of a running
086     * {@code FillTransition}. If the value of {@code shape} is changed for a
087     * running {@code FillTransition}, the animation has to be stopped and
088     * started again to pick up the new value.
089     */
090    private ObjectProperty<Shape> shape;
091    private static final Shape DEFAULT_SHAPE = null;
092
093    public final void setShape(Shape value) {
094        if ((shape != null) || (value != null /* DEFAULT_SHAPE */)) {
095            shapeProperty().set(value);
096        }
097    }
098
099    public final Shape getShape() {
100        return (shape == null)? DEFAULT_SHAPE : shape.get();
101    }
102
103    public final ObjectProperty<Shape> shapeProperty() {
104        if (shape == null) {
105            shape = new SimpleObjectProperty<Shape>(this, "shape", DEFAULT_SHAPE);
106        }
107        return shape;
108    }
109
110    private Shape cachedShape;
111
112    /**
113     * The duration of this {@code FillTransition}.
114     * <p>
115     * It is not possible to change the {@code duration} of a running
116     * {@code FillTransition}. If the value of {@code duration} is changed for a
117     * running {@code FillTransition}, the animation has to be stopped and
118     * started again to pick up the new value.
119     * <p>
120     * Note: While the unit of {@code duration} is a millisecond, the
121     * granularity depends on the underlying operating system and will in
122     * general be larger. For example animations on desktop systems usually run
123     * with a maximum of 60fps which gives a granularity of ~17 ms.
124     *
125     * Setting duration to value lower than {@link Duration#ZERO} will result
126     * in {@link IllegalArgumentException}.
127     * 
128     * @defaultValue 400ms
129     */
130    private ObjectProperty<Duration> duration;
131    private static final Duration DEFAULT_DURATION = Duration.millis(400);
132
133    public final void setDuration(Duration value) {
134        if ((duration != null) || (!DEFAULT_DURATION.equals(value))) {
135            durationProperty().set(value);
136        }
137    }
138
139    public final Duration getDuration() {
140        return (duration == null)? DEFAULT_DURATION : duration.get();
141    }
142
143    public final ObjectProperty<Duration> durationProperty() {
144        if (duration == null) {
145            duration = new ObjectPropertyBase<Duration>(DEFAULT_DURATION) {
146
147                @Override
148                public void invalidated() {
149                    try {
150                        setCycleDuration(getDuration());
151                    } catch (IllegalArgumentException e) {
152                        if (isBound()) {
153                            unbind();
154                        }
155                        set(getCycleDuration());
156                        throw e;
157                    }
158                }
159
160                @Override
161                public Object getBean() {
162                    return FillTransition.this;
163                }
164
165                @Override
166                public String getName() {
167                    return "duration";
168                }
169            };
170        }
171        return duration;
172    }
173
174    /**
175     * Specifies the start color value for this {@code FillTransition}.
176     * <p>
177     * It is not possible to change {@code fromValue} of a running
178     * {@code FillTransition}. If the value of {@code fromValue} is changed for
179     * a running {@code FillTransition}, the animation has to be stopped and
180     * started again to pick up the new value.
181     * 
182     * @defaultValue {@code null}
183     */
184    private ObjectProperty<Color> fromValue;
185    private static final Color DEFAULT_FROM_VALUE = null;
186
187    public final void setFromValue(Color value) {
188        if ((fromValue != null) || (value != null /* DEFAULT_FROM_VALUE */)) {
189            fromValueProperty().set(value);
190        }
191    }
192
193    public final Color getFromValue() {
194        return (fromValue == null)? DEFAULT_FROM_VALUE : fromValue.get();
195    }
196
197    public final ObjectProperty<Color> fromValueProperty() {
198        if (fromValue == null) {
199            fromValue = new SimpleObjectProperty<Color>(this, "fromValue", DEFAULT_FROM_VALUE);
200        }
201        return fromValue;
202    }
203
204    /**
205     * Specifies the stop color value for this {@code FillTransition}.
206     * <p>
207     * It is not possible to change {@code toValue} of a running
208     * {@code FillTransition}. If the value of {@code toValue} is changed for a
209     * running {@code FillTransition}, the animation has to be stopped and
210     * started again to pick up the new value.
211     * 
212     * @defaultValue {@code null}
213     */
214    private ObjectProperty<Color> toValue;
215    private static final Color DEFAULT_TO_VALUE = null;
216
217    public final void setToValue(Color value) {
218        if ((toValue != null) || (value != null /* DEFAULT_TO_VALUE */)) {
219            toValueProperty().set(value);
220        }
221    }
222
223    public final Color getToValue() {
224        return (toValue == null)? DEFAULT_TO_VALUE : toValue.get();
225    }
226
227    public final ObjectProperty<Color> toValueProperty() {
228        if (toValue == null) {
229            toValue = new SimpleObjectProperty<Color>(this, "toValue", DEFAULT_TO_VALUE);
230        }
231        return toValue;
232    }
233
234/**
235         * The constructor of {@code FillTransition}
236         * @param duration The duration of the {@code FillTransition}
237         * @param shape The {@code shape} which filling will be animated
238         * @param fromValue The start value of the color-animation
239         * @param toValue The end value of the color-animation
240         */
241    public FillTransition(Duration duration, Shape shape, Color fromValue,
242            Color toValue) {
243        setDuration(duration);
244        setShape(shape);
245        setFromValue(fromValue);
246        setToValue(toValue);
247        setCycleDuration(duration);
248    }
249
250/**
251         * The constructor of {@code FillTransition}
252         * @param duration The duration of the {@code FillTransition}
253         * @param fromValue The start value of the color-animation
254         * @param toValue The end value of the color-animation
255         */
256    public FillTransition(Duration duration, Color fromValue, Color toValue) {
257        this(duration, null, fromValue, toValue);
258    }
259
260    /**
261     * The constructor of {@code FillTransition}
262     * 
263     * @param duration
264     *            The duration of the {@code FillTransition}
265     * @param shape
266     *            The {@code shape} which filling will be animated
267     */
268    public FillTransition(Duration duration, Shape shape) {
269        this(duration, shape, null, null);
270    }
271
272    /**
273     * The constructor of {@code FillTransition}
274     * 
275     * @param duration
276     *            The duration of the {@code FadeTransition}
277     */
278    public FillTransition(Duration duration) {
279        this(duration, null, null, null);
280    }
281
282    /**
283     * The constructor of {@code FillTransition}
284     */
285    public FillTransition() {
286        this(DEFAULT_DURATION, null);
287    }
288
289    /**
290     * {@inheritDoc}
291     */
292    @Override
293    protected void interpolate(double frac) {
294        final Color newColor = start.interpolate(end, frac);
295        cachedShape.setFill(newColor);
296    }
297
298    private Shape getTargetShape() {
299        Shape shape = getShape();
300        if (shape == null) {
301            final Node node = getParentTargetNode();
302            if (node instanceof Shape) {
303                shape = (Shape) node;
304            }
305        }
306        return shape;
307    }
308
309    @Override 
310    boolean impl_startable(boolean forceSync) {
311        if (!super.impl_startable(forceSync)) {
312            return false;
313        }
314        // check if synchronization is not forced and cached values are valid
315        if (!forceSync && (cachedShape != null)) {
316            return true;
317        }
318
319        // we have to synchronize
320        final Shape shape = getTargetShape();
321        return ((shape != null) // shape is defined?
322                && ((getFromValue() != null) || (shape.getFill() instanceof Color)) // fromValue
323                                                                                    // defined
324                                                                                    // or
325                                                                                    // current
326                                                                                    // fill
327                                                                                    // is
328                                                                                    // Color?
329        && (getToValue() != null)); // toValue defined?
330    }
331
332    @Override 
333    void impl_sync(boolean forceSync) {
334        super.impl_sync(forceSync);
335        if (forceSync || (cachedShape == null)) {
336            cachedShape = getTargetShape();
337            final Color _fromValue = getFromValue();
338            start = (_fromValue != null) ? _fromValue : (Color) cachedShape
339                    .getFill();
340            end = getToValue();
341        }
342    }
343}