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.beans.property.ObjectPropertyBase;
032import javafx.scene.Node;
033
034import com.sun.javafx.Utils;
035import com.sun.javafx.effect.EffectDirtyBits;
036import com.sun.javafx.effect.EffectUtils;
037import com.sun.javafx.geom.BaseBounds;
038import com.sun.javafx.geom.RectBounds;
039import com.sun.javafx.geom.transform.BaseTransform;
040import com.sun.javafx.scene.BoundsAccessor;
041import com.sun.scenario.effect.Blend.Mode;
042
043
044/**
045 * An effect that blends the two inputs together using one of the
046 * pre-defined {@link BlendMode}s.
047 *
048 * <p>
049 * Example:
050 * <pre><code>
051 * Blend blend = new Blend();
052 * blend.setMode(BlendMode.COLOR_BURN);
053 *
054 * ColorInput colorInput = new ColorInput();
055 * colorInput.setPaint(Color.STEELBLUE);
056 * colorInput.setX(10);
057 * colorInput.setY(10);
058 * colorInput.setWidth(100);
059 * colorInput.setHeight(180);
060 *
061 * blend.setTopInput(colorInput);
062 *
063 * Rectangle rect = new Rectangle();
064 * rect.setWidth(220);
065 * rect.setHeight(100);
066 * Stop[] stops = new Stop[]{new Stop(0, Color.LIGHTSTEELBLUE), new Stop(1, Color.PALEGREEN)};
067 * LinearGradient lg = new LinearGradient(0, 0, 0.25, 0.25, true, CycleMethod.REFLECT, stops);
068 * rect.setFill(lg);
069 *
070 * Text text = new Text();
071 * text.setX(15);
072 * text.setY(65);
073 * text.setFill(Color.PALEVIOLETRED);
074 * text.setText("COLOR_BURN");
075 * text.setFont(Font.font(null, FontWeight.BOLD, 30));
076 *
077 * Group g = new Group();
078 * g.setEffect(blend);
079 * g.getChildren().addAll(rect, text);
080 * </pre></code>
081 *
082 * <p> The code above produces the following: </p> 
083 * <p> <img src="doc-files/blend.png"/> </p>
084 */
085public class Blend extends Effect {
086
087    static private Mode toPGMode(BlendMode mode) {
088        if (mode == null) {
089            return Mode.SRC_OVER; // Default value
090        } else if (mode == BlendMode.SRC_OVER) {
091            return Mode.SRC_OVER;
092        } else if (mode == BlendMode.SRC_ATOP) {
093            return Mode.SRC_ATOP;
094        } else if (mode == BlendMode.ADD) {
095            return Mode.ADD;
096        } else if (mode == BlendMode.MULTIPLY) {
097            return Mode.MULTIPLY;
098        } else if (mode == BlendMode.SCREEN) {
099            return Mode.SCREEN;
100        } else if (mode == BlendMode.OVERLAY) {
101            return Mode.OVERLAY;
102        } else if (mode == BlendMode.DARKEN) {
103            return Mode.DARKEN;
104        } else if (mode == BlendMode.LIGHTEN) {
105            return Mode.LIGHTEN;
106        } else if (mode == BlendMode.COLOR_DODGE) {
107            return Mode.COLOR_DODGE;
108        } else if (mode == BlendMode.COLOR_BURN) {
109            return Mode.COLOR_BURN;
110        } else if (mode == BlendMode.HARD_LIGHT) {
111            return Mode.HARD_LIGHT;
112        } else if (mode == BlendMode.SOFT_LIGHT) {
113            return Mode.SOFT_LIGHT;
114        } else if (mode == BlendMode.DIFFERENCE) {
115            return Mode.DIFFERENCE;
116        } else if (mode == BlendMode.EXCLUSION) {
117            return Mode.EXCLUSION;
118        } else if (mode == BlendMode.RED) {
119            return Mode.RED;
120        } else if (mode == BlendMode.GREEN) {
121            return Mode.GREEN;
122        } else if (mode == BlendMode.BLUE) {
123            return Mode.BLUE;
124        } else {
125            throw new java.lang.AssertionError("Unrecognized blend mode: {mode}");
126        }
127    }
128
129    /**
130     * Used by Group to convert the FX BlendMode enum value into a Decora value.
131     * @treatAsPrivate implementation detail
132     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
133     */
134    @Deprecated
135    public static Mode impl_getToolkitMode(BlendMode mode) {
136        return toPGMode(mode);
137    }
138
139    /**
140     * Creates a new instance of Blend with default parameters.
141     */
142    public Blend() {}
143
144    /**
145     * Creates a new instance of Blend with the specified mode.
146     * @param mode the {@code BlendMode} used to blend the two inputs together
147     */
148    public Blend(BlendMode mode) {
149        setMode(mode);
150    }
151
152    /**
153     * Creates a new instance of Blend with the specified mode and bottom
154     * and top inputs.
155     * @param mode the {@code BlendMode} used to blend the two inputs together
156     * @param bottomInput the bottom input for this {@code Blend} operation
157     * @param topInput the top input for this {@code Blend} operation
158     */
159    public Blend(BlendMode mode, Effect bottomInput, Effect topInput) {
160        setMode(mode);
161        setBottomInput(bottomInput);
162        setTopInput(topInput);
163    }
164
165    @Override
166    com.sun.scenario.effect.Blend impl_createImpl() {
167        return new com.sun.scenario.effect.Blend(
168                        toPGMode(BlendMode.SRC_OVER),
169                        com.sun.scenario.effect.Effect.DefaultInput,
170                        com.sun.scenario.effect.Effect.DefaultInput);
171    }
172
173    /**
174     * The {@code BlendMode} used to blend the two inputs together.
175     * <pre>
176     *       Min: n/a
177     *       Max: n/a
178     *   Default: BlendMode.SRC_OVER
179     *  Identity: n/a
180     * </pre>
181     * @defaultValue SRC_OVER
182     */
183    private ObjectProperty<BlendMode> mode;
184
185
186    public final void setMode(BlendMode value) {
187        modeProperty().set(value);
188    }
189
190    public final BlendMode getMode() {
191        return mode == null ? BlendMode.SRC_OVER : mode.get();
192    }
193
194    public final ObjectProperty<BlendMode> modeProperty() {
195        if (mode == null) {
196            mode = new ObjectPropertyBase<BlendMode>(BlendMode.SRC_OVER) {
197
198                @Override
199                public void invalidated() {
200                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
201                }
202
203                @Override
204                public Object getBean() {
205                    return Blend.this;
206                }
207
208                @Override
209                public String getName() {
210                    return "mode";
211                }
212            };
213        }
214        return mode;
215    }
216
217    /**
218     * The opacity value, which is modulated with the top input prior
219     * to blending.
220     * <pre>
221     *       Min: 0.0
222     *       Max: 1.0
223     *   Default: 1.0
224     *  Identity: 1.0
225     * </pre>
226     * @defaultValue 1.0
227     */
228    private DoubleProperty opacity;
229
230
231    public final void setOpacity(double value) {
232        opacityProperty().set(value);
233    }
234
235    public final double getOpacity() {
236        return opacity == null ? 1 : opacity.get();
237    }
238
239    public final DoubleProperty opacityProperty() {
240        if (opacity == null) {
241            opacity = new DoublePropertyBase(1) {
242
243                @Override
244                public void invalidated() {
245                    markDirty(EffectDirtyBits.EFFECT_DIRTY);
246                }
247
248                @Override
249                public Object getBean() {
250                    return Blend.this;
251                }
252
253                @Override
254                public String getName() {
255                    return "opacity";
256                }
257            };
258        }
259        return opacity;
260    }
261
262    /**
263     * The bottom input for this {@code Blend} operation.
264     * If set to {@code null}, or left unspecified, a graphical image of
265     * the {@code Node} to which the {@code Effect} is attached will be
266     * used as the input.
267     * @defaultValue null
268     */
269    private ObjectProperty<Effect> bottomInput;
270
271
272    public final void setBottomInput(Effect value) {
273        bottomInputProperty().set(value);
274    }
275
276    public final Effect getBottomInput() {
277        return bottomInput == null ? null : bottomInput.get();
278    }
279
280    public final ObjectProperty<Effect> bottomInputProperty() {
281        if (bottomInput == null) {
282            bottomInput = new EffectInputProperty("bottomInput");
283        }
284        return bottomInput;
285    }
286
287    /**
288     * The top input for this {@code Blend} operation.
289     * If set to {@code null}, or left unspecified, a graphical image of
290     * the {@code Node} to which the {@code Effect} is attached will be
291     * used as the input.
292     * @defaultValue null
293     */
294    private ObjectProperty<Effect> topInput;
295
296
297    public final void setTopInput(Effect value) {
298        topInputProperty().set(value);
299    }
300
301    public final Effect getTopInput() {
302        return topInput == null ? null : topInput.get();
303    }
304
305    public final ObjectProperty<Effect> topInputProperty() {
306        if (topInput == null) {
307            topInput = new EffectInputProperty("topInput");
308        }
309        return topInput;
310    }
311
312    @Override
313    boolean impl_checkChainContains(Effect e) {
314        Effect localTopInput = getTopInput();
315        Effect localBottomInput = getBottomInput();
316        if (localTopInput == e || localBottomInput == e)
317            return true;
318        if (localTopInput != null && localTopInput.impl_checkChainContains(e))
319            return true;
320        if (localBottomInput != null && localBottomInput.impl_checkChainContains(e))
321            return true;
322
323        return false;
324    }
325
326    @Override
327    void impl_update() {
328        Effect localBottomInput = getBottomInput();
329        Effect localTopInput = getTopInput();
330
331        if (localTopInput != null) {
332            localTopInput.impl_sync();
333        }
334        if (localBottomInput != null) {
335            localBottomInput.impl_sync();
336        }
337
338        com.sun.scenario.effect.Blend peer =
339                (com.sun.scenario.effect.Blend) impl_getImpl();
340        peer.setTopInput(localTopInput == null ? null : localTopInput.impl_getImpl());
341        peer.setBottomInput(localBottomInput == null ? null : localBottomInput.impl_getImpl());
342        peer.setOpacity((float)Utils.clamp(0, getOpacity(), 1));
343        peer.setMode(toPGMode(getMode()));
344    }
345
346    /**
347     * @treatAsPrivate implementation detail
348     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
349     */
350    @Deprecated
351    @Override
352    public BaseBounds impl_getBounds(BaseBounds bounds,
353                                     BaseTransform tx,
354                                     Node node,
355                                     BoundsAccessor boundsAccessor) {
356        BaseBounds topBounds = new RectBounds();
357        BaseBounds bottomBounds = new RectBounds();
358        bottomBounds = EffectUtils.getInputBounds(bottomBounds, tx,
359                                                  node, boundsAccessor,
360                                                  getBottomInput());
361        topBounds = EffectUtils.getInputBounds(topBounds, tx,
362                                               node, boundsAccessor,
363                                               getTopInput());
364        BaseBounds ret = topBounds.deriveWithUnion(bottomBounds);
365        return ret;
366    }
367    
368    /**
369     * 
370     * @treatAsPrivate implementation detail
371     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
372     */
373    @Deprecated
374    @Override
375    public Effect impl_copy() {
376        return new Blend(this.getMode(), this.getBottomInput(), this.getTopInput());
377    }
378}