Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 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.scene.effect;
027
028import javafx.beans.property.DoubleProperty;
029import javafx.beans.property.DoublePropertyBase;
030import javafx.beans.property.ObjectProperty;
031import javafx.scene.Node;
032
033import com.sun.javafx.Utils;
034import com.sun.javafx.effect.EffectDirtyBits;
035import com.sun.javafx.effect.EffectUtils;
036import com.sun.javafx.geom.BaseBounds;
037import com.sun.javafx.geom.transform.BaseTransform;
038import com.sun.javafx.scene.BoundsAccessor;
039
040
041/**
042 * An effect that renders a reflected version of the input below the
043 * actual input content.
044 * <p>
045 * Note that the reflection of a {@code Node} with a {@code Reflection}
046 * effect installed will not respond to mouse events or the containment
047 * methods on the {@code Node}.
048 * 
049 * <p>
050 * Example:
051 * <pre><code>
052 * Reflection reflection = new Reflection();
053 * reflection.setFraction(0.7);
054 * 
055 * Text text = new Text();
056 * text.setX(10.0);
057 * text.setY(50.0);
058 * text.setCache(true);
059 * text.setText("Reflections on JavaFX...");
060 * text.setFill(Color.web("0x3b596d"));
061 * text.setFont(Font.font(null, FontWeight.BOLD, 40));
062 * text.setEffect(reflection);
063 * </pre></code> 
064 * <p> The code above produces the following: </p>
065 * <p>
066 * <img src="doc-files/reflection.png"/>
067 * </p>
068 */
069public class Reflection extends Effect {
070    /**
071     * Creates a new instance of Reflection with default parameters.
072     */
073    public Reflection() {}
074
075    /**
076     * Creates a new instance of Reflection with the specified topOffset, fraction,
077     * topOpacity and bottomOpacity.
078     * @param topOffset the distance between the bottom of the input and the top of the reflection
079     * @param fraction the fraction of the input that is visible in the reflection
080     * @param topOpacity the opacity of the reflection at its top extreme
081     * @param bottomOpacity the opacity of the reflection at its bottom extreme
082     */
083    public Reflection(double topOffset, double fraction, 
084                      double topOpacity, double bottomOpacity) {
085        setBottomOpacity(bottomOpacity);
086        setTopOffset(topOffset);
087        setTopOpacity(topOpacity);
088        setFraction(fraction);
089    }
090 
091    @Override
092    com.sun.scenario.effect.Reflection impl_createImpl() {
093        return new com.sun.scenario.effect.Reflection();
094    };
095    /**
096     * The input for this {@code Effect}.
097     * If set to {@code null}, or left unspecified, a graphical image of
098     * the {@code Node} to which the {@code Effect} is attached will be
099     * used as the input.
100     * @defaultValue null
101     */
102    private ObjectProperty<Effect> input;
103
104
105    public final void setInput(Effect value) {
106        inputProperty().set(value);
107    }
108
109    public final Effect getInput() {
110        return input == null ? null : input.get();
111    }
112
113    public final ObjectProperty<Effect> inputProperty() {
114        if (input == null) {
115            input = new EffectInputProperty("input");
116        }
117        return input;
118    }
119
120    @Override
121    boolean impl_checkChainContains(Effect e) {
122        Effect localInput = getInput();
123        if (localInput == null)
124            return false;
125        if (localInput == e)
126            return true;
127        return localInput.impl_checkChainContains(e);
128    }
129
130    /**
131     * The top offset adjustment, which is the distance between the
132     * bottom of the input and the top of the reflection.
133     * <pre>
134     *       Min: n/a
135     *       Max: n/a
136     *   Default: 0.0
137     *  Identity: 0.0
138     * </pre>
139     * @defaultValue 0.0
140     */
141    private DoubleProperty topOffset;
142
143
144    public final void setTopOffset(double value) {
145        topOffsetProperty().set(value);
146    }
147
148    public final double getTopOffset() {
149        return topOffset == null ? 0 : topOffset.get();
150    }
151
152    public final DoubleProperty topOffsetProperty() {
153        if (topOffset == null) {
154            topOffset = new DoublePropertyBase() {
155
156                @Override
157                public void invalidated() {
158                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
159                    effectBoundsChanged();
160                }
161
162                @Override
163                public Object getBean() {
164                    return Reflection.this;
165                }
166
167                @Override
168                public String getName() {
169                    return "topOffset";
170                }
171            };
172        }
173        return topOffset;
174    }
175
176    /**
177     * The top opacity value, which is the opacity of the reflection
178     * at its top extreme.
179     * <pre>
180     *       Min: 0.0
181     *       Max: 1.0
182     *   Default: 0.5
183     *  Identity: 1.0
184     * </pre>
185     * @defaultValue 0.5
186     */
187    private DoubleProperty topOpacity;
188
189
190    public final void setTopOpacity(double value) {
191        topOpacityProperty().set(value);
192    }
193
194    public final double getTopOpacity() {
195        return topOpacity == null ? 0.5 : topOpacity.get();
196    }
197
198    public final DoubleProperty topOpacityProperty() {
199        if (topOpacity == null) {
200            topOpacity = new DoublePropertyBase(0.5) {
201
202                @Override
203                public void invalidated() {
204                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
205                }
206
207                @Override
208                public Object getBean() {
209                    return Reflection.this;
210                }
211
212                @Override
213                public String getName() {
214                    return "topOpacity";
215                }
216            };
217        }
218        return topOpacity;
219    }
220
221    /**
222     * The bottom opacity value, which is the opacity of the reflection
223     * at its bottom extreme.
224     * <pre>
225     *       Min: 0.0
226     *       Max: 1.0
227     *   Default: 0.0
228     *  Identity: 1.0
229     * </pre>
230     * @defaultValue 0.0
231     */
232    private DoubleProperty bottomOpacity;
233
234
235    public final void setBottomOpacity(double value) {
236        bottomOpacityProperty().set(value);
237    }
238
239    public final double getBottomOpacity() {
240        return bottomOpacity == null ? 0 : bottomOpacity.get();
241    }
242
243    public final DoubleProperty bottomOpacityProperty() {
244        if (bottomOpacity == null) {
245            bottomOpacity = new DoublePropertyBase() {
246
247                @Override
248                public void invalidated() {
249                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
250                }
251
252                @Override
253                public Object getBean() {
254                    return Reflection.this;
255                }
256
257                @Override
258                public String getName() {
259                    return "bottomOpacity";
260                }
261            };
262        }
263        return bottomOpacity;
264    }
265
266    /**
267     * The fraction of the input that is visible in the reflection.
268     * For example, a value of 0.5 means that only the bottom half of the
269     * input will be visible in the reflection.
270     * <pre>
271     *       Min: 0.0
272     *       Max: 1.0
273     *   Default: 0.75
274     *  Identity: 1.0
275     * </pre>
276     * @defaultValue 0.75
277     */
278    private DoubleProperty fraction;
279
280
281    public final void setFraction(double value) {
282        fractionProperty().set(value);
283    }
284
285    public final double getFraction() {
286        return fraction == null ? 0.75 : fraction.get();
287    }
288
289    public final DoubleProperty fractionProperty() {
290        if (fraction == null) {
291            fraction = new DoublePropertyBase(0.75) {
292
293                @Override
294                public void invalidated() {
295                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
296                    effectBoundsChanged();
297                }
298
299                @Override
300                public Object getBean() {
301                    return Reflection.this;
302                }
303
304                @Override
305                public String getName() {
306                    return "fraction";
307                }
308            };
309        }
310        return fraction;
311    }
312
313    private float getClampedFraction() {
314        return (float)Utils.clamp(0, getFraction(), 1);
315    }
316
317    private float getClampedBottomOpacity() {
318        return (float)Utils.clamp(0, getBottomOpacity(), 1);
319    }
320
321    private float getClampedTopOpacity() {
322        return (float)Utils.clamp(0, getTopOpacity(), 1);
323    }
324
325    @Override
326    void impl_update() {
327        Effect localInput = getInput();
328        if (localInput != null) {
329            localInput.impl_sync();
330        }
331
332        com.sun.scenario.effect.Reflection peer =
333                (com.sun.scenario.effect.Reflection) impl_getImpl();
334        peer.setInput(localInput == null ? null : localInput.impl_getImpl());
335        peer.setFraction(getClampedFraction());
336        peer.setTopOffset((float)getTopOffset());
337        peer.setBottomOpacity(getClampedBottomOpacity());
338        peer.setTopOpacity(getClampedTopOpacity());
339    }
340
341    /**
342     * @treatAsPrivate implementation detail
343     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
344     */
345    @Deprecated
346    @Override
347    public BaseBounds impl_getBounds(BaseBounds bounds,
348                                     BaseTransform tx,
349                                     Node node,
350                                     BoundsAccessor boundsAccessor) {
351        bounds = EffectUtils.getInputBounds(bounds,
352                                            BaseTransform.IDENTITY_TRANSFORM,
353                                            node, boundsAccessor,
354                                            getInput());
355        bounds.roundOut();
356
357        float x1 = bounds.getMinX();
358        float y1 = bounds.getMaxY() + (float)getTopOffset();
359        float z1 = bounds.getMinZ();
360        float x2 = bounds.getMaxX();
361        float y2 = y1 + (getClampedFraction() * bounds.getHeight());
362        float z2 = bounds.getMaxZ();
363
364        BaseBounds ret = BaseBounds.getInstance(x1, y1, z1, x2, y2, z2);
365        ret = ret.deriveWithUnion(bounds);
366
367        return EffectUtils.transformBounds(tx, ret);
368    }
369
370    /**
371     * 
372     * @treatAsPrivate implementation detail
373     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
374     */
375    @Deprecated
376    @Override
377    public Effect impl_copy() {
378        Reflection ref = new Reflection(this.getTopOffset(), this.getFraction(), 
379                this.getTopOpacity(), this.getBottomOpacity());
380        ref.setInput(ref.getInput());        
381        return ref;
382    }
383}