rev 8703 : RT-40186: Update copyright header for files modified in 2015
1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javafx.scene.effect;
27
28 import javafx.beans.property.DoubleProperty;
29 import javafx.beans.property.DoublePropertyBase;
30 import javafx.beans.property.ObjectProperty;
31 import javafx.beans.property.ObjectPropertyBase;
32 import javafx.scene.Node;
33 import javafx.scene.paint.Color;
34
35 import com.sun.javafx.util.Utils;
36 import com.sun.javafx.effect.EffectDirtyBits;
37 import com.sun.javafx.geom.BaseBounds;
38 import com.sun.javafx.geom.transform.BaseTransform;
39 import com.sun.javafx.scene.BoundsAccessor;
40 import com.sun.javafx.tk.Toolkit;
41
42
43 /**
44 * A high-level effect that renders a shadow inside the edges of the
45 * given content with the specified color, radius, and offset.
46 *
47 * <p>
48 * Example:
49 * <pre><code>
50 * InnerShadow innerShadow = new InnerShadow();
51 * innerShadow.setOffsetX(4);
52 * innerShadow.setOffsetY(4);
53 * innerShadow.setColor(Color.web("0x3b596d"));
54 *
55 * Text text = new Text();
56 * text.setEffect(innerShadow);
57 * text.setX(20);
58 * text.setY(100);
59 * text.setText("InnerShadow");
60 * text.setFill(Color.ALICEBLUE);
61 * text.setFont(Font.font(null, FontWeight.BOLD, 50));
62 * </pre></code>
63 * <p> The code above produces the following: </p>
64 * <p>
65 * <img * src="doc-files/innershadow.png"/>
66 * </p>
67 * @since JavaFX 2.0
68 */
69 public class InnerShadow extends Effect {
70 private boolean changeIsLocal;
71
72 /**
73 * Creates a new instance of InnerShadow with default parameters.
74 */
75 public InnerShadow() {}
76
77 /**
78 * Creates a new instance of InnerShadow with specified radius and color.
79 * @param radius the radius of the shadow blur kernel
80 * @param color the shadow {@code Color}
81 */
82 public InnerShadow(double radius, Color color) {
83 setRadius(radius);
84 setColor(color);
85 }
86
87 /**
88 * Creates a new instance of InnerShadow with specified radius, offsetX,
89 * offsetY and color.
90 * @param radius the radius of the shadow blur kernel
91 * @param offsetX the shadow offset in the x direction
92 * @param offsetY the shadow offset in the y direction
93 * @param color the shadow {@code Color}
94 */
95 public InnerShadow(double radius, double offsetX, double offsetY, Color color) {
96 setRadius(radius);
97 setOffsetX(offsetX);
98 setOffsetY(offsetY);
99 setColor(color);
100 }
101
102 /**
103 * Creates a new instance of InnerShadow with the specified blurType, color,
104 * radius, spread, offsetX and offsetY.
105 * @param blurType the algorithm used to blur the shadow
106 * @param color the shadow {@code Color}
107 * @param radius the radius of the shadow blur kernel
108 * @param choke the portion of the radius where the contribution of
109 * the source material will be 100%
110 * @param offsetX the shadow offset in the x direction
111 * @param offsetY the shadow offset in the y direction
112 * @since JavaFX 2.1
113 */
114 public InnerShadow(BlurType blurType, Color color, double radius, double choke,
115 double offsetX, double offsetY) {
116 setBlurType(blurType);
117 setColor(color);
118 setRadius(radius);
119 setChoke(choke);
120 setOffsetX(offsetX);
121 setOffsetY(offsetY);
122 }
123
124 @Override
125 com.sun.scenario.effect.InnerShadow impl_createImpl() {
126 return new com.sun.scenario.effect.InnerShadow();
127 };
128
129 /**
130 * The input for this {@code Effect}.
131 * If set to {@code null}, or left unspecified, a graphical image of
132 * the {@code Node} to which the {@code Effect} is attached will be
133 * used as the input.
134 * @defaultValue null
135 */
136 private ObjectProperty<Effect> input;
137
138
139 public final void setInput(Effect value) {
140 inputProperty().set(value);
141 }
142
143 public final Effect getInput() {
144 return input == null ? null : input.get();
145 }
146
147 public final ObjectProperty<Effect> inputProperty() {
148 if (input == null) {
149 input = new EffectInputProperty("input");
150 }
151 return input;
152 }
153
154 @Override
155 boolean impl_checkChainContains(Effect e) {
156 Effect localInput = getInput();
157 if (localInput == null)
158 return false;
159 if (localInput == e)
160 return true;
161 return localInput.impl_checkChainContains(e);
162 }
163
164 /**
165 * The radius of the shadow blur kernel.
166 * This attribute controls the distance that the shadow is spread
167 * to each side of the source pixels.
168 * Setting the radius is equivalent to setting both the {@code width}
169 * and {@code height} attributes to a value of {@code (2 * radius + 1)}.
170 * <pre>
171 * Min: 0.0
172 * Max: 127.0
173 * Default: 10.0
174 * Identity: 0.0
175 * </pre>
176 * @defaultValue 10.0
177 */
178 private DoubleProperty radius;
179
180
181 public final void setRadius(double value) {
182 radiusProperty().set(value);
183 }
184
185 public final double getRadius() {
186 return radius == null ? 10 : radius.get();
187 }
188
189 public final DoubleProperty radiusProperty() {
190 if (radius == null) {
191 radius = new DoublePropertyBase(10) {
192
193 @Override
194 public void invalidated() {
195 // gettter here is necessary to make the property valid
196 double localRadius = getRadius();
197 if (!changeIsLocal) {
198 changeIsLocal = true;
199 updateRadius(localRadius);
200 changeIsLocal = false;
201 markDirty(EffectDirtyBits.EFFECT_DIRTY);
202 effectBoundsChanged();
203 }
204 }
205
206 @Override
207 public Object getBean() {
208 return InnerShadow.this;
209 }
210
211 @Override
212 public String getName() {
213 return "radius";
214 }
215 };
216 }
217 return radius;
218 }
219
220 private void updateRadius(double value) {
221 double newdim = (value * 2 + 1);
222 if (width != null && width.isBound()) {
223 if (height == null || !height.isBound()) {
224 setHeight(newdim * 2 - getWidth());
225 }
226 } else if (height != null && height.isBound()) {
227 setWidth(newdim * 2 - getHeight());
228 } else {
229 setWidth(newdim);
230 setHeight(newdim);
231 }
232 }
233
234 /**
235 * The horizontal size of the shadow blur kernel.
236 * This attribute controls the horizontal size of the total area over
237 * which the shadow of a single pixel is distributed by the blur algorithm.
238 * Values less than {@code 1.0} are not distributed beyond the original
239 * pixel and so have no blurring effect on the shadow.
240 * <pre>
241 * Min: 0.0
242 * Max: 255.0
243 * Default: 21.0
244 * Identity: <1.0
245 * </pre>
246 * @defaultValue 21.0
247 */
248 private DoubleProperty width;
249
250
251 public final void setWidth(double value) {
252 widthProperty().set(value);
253 }
254
255 public final double getWidth() {
256 return width == null ? 21 : width.get();
257 }
258
259 public final DoubleProperty widthProperty() {
260 if (width == null) {
261 width = new DoublePropertyBase(21) {
262
263 @Override
264 public void invalidated() {
265 // gettter here is necessary to make the property valid
266 double localWidth = getWidth();
267 if (!changeIsLocal) {
268 changeIsLocal = true;
269 updateWidth(localWidth);
270 changeIsLocal = false;
271 markDirty(EffectDirtyBits.EFFECT_DIRTY);
272 effectBoundsChanged();
273 }
274 }
275
276 @Override
277 public Object getBean() {
278 return InnerShadow.this;
279 }
280
281 @Override
282 public String getName() {
283 return "width";
284 }
285 };
286 }
287 return width;
288 }
289
290 private void updateWidth(double value) {
291 if (radius == null || !radius.isBound()) {
292 double newrad = ((value + getHeight()) / 2);
293 newrad = ((newrad - 1) / 2);
294 if (newrad < 0) {
295 newrad = 0;
296 }
297 setRadius(newrad);
298 } else {
299 if (height == null || !height.isBound()) {
300 double newdim = (getRadius() * 2 + 1);
301 setHeight(newdim * 2 - value);
302 }
303 }
304 }
305
306 /**
307 * The vertical size of the shadow blur kernel.
308 * This attribute controls the vertical size of the total area over
309 * which the shadow of a single pixel is distributed by the blur algorithm.
310 * Values less than {@code 1.0} are not distributed beyond the original
311 * pixel and so have no blurring effect on the shadow.
312 * <pre>
313 * Min: 0.0
314 * Max: 255.0
315 * Default: 21.0
316 * Identity: <1.0
317 * </pre>
318 * @defaultValue 21.0
319 */
320 private DoubleProperty height;
321
322
323 public final void setHeight(double value) {
324 heightProperty().set(value);
325 }
326
327 public final double getHeight() {
328 return height == null ? 21 : height.get();
329 }
330
331 public final DoubleProperty heightProperty() {
332 if (height == null) {
333 height = new DoublePropertyBase(21) {
334
335 @Override
336 public void invalidated() {
337 // gettter here is necessary to make the property valid
338 double localHeight = getHeight();
339 if (!changeIsLocal) {
340 changeIsLocal = true;
341 updateHeight(localHeight);
342 changeIsLocal = false;
343 markDirty(EffectDirtyBits.EFFECT_DIRTY);
344 effectBoundsChanged();
345 }
346 }
347
348 @Override
349 public Object getBean() {
350 return InnerShadow.this;
351 }
352
353 @Override
354 public String getName() {
355 return "height";
356 }
357 };
358 }
359 return height;
360 }
361 private void updateHeight(double value) {
362 if (radius == null || !radius.isBound()) {
363 double newrad = ((getWidth() + value) / 2);
364 newrad = ((newrad - 1) / 2);
365 if (newrad < 0) {
366 newrad = 0;
367 }
368 setRadius(newrad);
369 } else {
370 if (width == null || !width.isBound()) {
371 double newdim = (getRadius() * 2 + 1);
372 setWidth(newdim * 2 - value);
373 }
374 }
375 }
376
377 /**
378 * The algorithm used to blur the shadow.
379 * <pre>
380 * Min: n/a
381 * Max: n/a
382 * Default: BlurType.THREE_PASS_BOX
383 * Identity: n/a
384 * </pre>
385 * @defaultValue THREE_PASS_BOX
386 */
387 private ObjectProperty<BlurType> blurType;
388
389
390 public final void setBlurType(BlurType value) {
391 blurTypeProperty().set(value);
392 }
393
394 public final BlurType getBlurType() {
395 return blurType == null ? BlurType.THREE_PASS_BOX : blurType.get();
396 }
397
398 public final ObjectProperty<BlurType> blurTypeProperty() {
399 if (blurType == null) {
400 blurType = new ObjectPropertyBase<BlurType>(BlurType.THREE_PASS_BOX) {
401
402 @Override
403 public void invalidated() {
404 markDirty(EffectDirtyBits.EFFECT_DIRTY);
405 }
406
407 @Override
408 public Object getBean() {
409 return InnerShadow.this;
410 }
411
412 @Override
413 public String getName() {
414 return "blurType";
415 }
416 };
417 }
418 return blurType;
419 }
420
421 /**
422 * The choke of the shadow.
423 * The choke is the portion of the radius where the contribution of
424 * the source material will be 100%.
425 * The remaining portion of the radius will have a contribution
426 * controlled by the blur kernel.
427 * A choke of {@code 0.0} will result in a distribution of the
428 * shadow determined entirely by the blur algorithm.
429 * A choke of {@code 1.0} will result in a solid growth inward of the
430 * shadow from the edges to the limit of the radius with a very sharp
431 * cutoff to transparency inside the radius.
432 * <pre>
433 * Min: 0.0
434 * Max: 1.0
435 * Default: 0.0
436 * Identity: 0.0
437 * </pre>
438 * @defaultValue 0.0
439 */
440 private DoubleProperty choke;
441
442
443 public final void setChoke(double value) {
444 chokeProperty().set(value);
445 }
446
447 public final double getChoke() {
448 return choke == null ? 0 : choke.get();
449 }
450
451 public final DoubleProperty chokeProperty() {
452 if (choke == null) {
453 choke = new DoublePropertyBase() {
454
455 @Override
456 public void invalidated() {
457 markDirty(EffectDirtyBits.EFFECT_DIRTY);
458 }
459
460 @Override
461 public Object getBean() {
462 return InnerShadow.this;
463 }
464
465 @Override
466 public String getName() {
467 return "choke";
468 }
469 };
470 }
471 return choke;
472 }
473
474 /**
475 * The shadow {@code Color}.
476 * <pre>
477 * Min: n/a
478 * Max: n/a
479 * Default: Color.BLACK
480 * Identity: n/a
481 * </pre>
482 * @defaultValue BLACK
483 */
484 private ObjectProperty<Color> color;
485
486
487 public final void setColor(Color value) {
488 colorProperty().set(value);
489 }
490
491 public final Color getColor() {
492 return color == null ? Color.BLACK : color.get();
493 }
494
495 public final ObjectProperty<Color> colorProperty() {
496 if (color == null) {
497 color = new ObjectPropertyBase<Color>(Color.BLACK) {
498
499 @Override
500 public void invalidated() {
501 markDirty(EffectDirtyBits.EFFECT_DIRTY);
502 }
503
504 @Override
505 public Object getBean() {
506 return InnerShadow.this;
507 }
508
509 @Override
510 public String getName() {
511 return "color";
512 }
513 };
514 }
515 return color;
516 }
517
518 /**
519 * The shadow offset in the x direction, in pixels.
520 * <pre>
521 * Min: n/a
522 * Max: n/a
523 * Default: 0.0
524 * Identity: 0.0
525 * </pre>
526 * @defaultValue 0.0
527 */
528 private DoubleProperty offsetX;
529
530
531 public final void setOffsetX(double value) {
532 offsetXProperty().set(value);
533 }
534
535 public final double getOffsetX() {
536 return offsetX == null ? 0 : offsetX.get();
537 }
538
539 public final DoubleProperty offsetXProperty() {
540 if (offsetX == null) {
541 offsetX = new DoublePropertyBase() {
542
543 @Override
544 public void invalidated() {
545 markDirty(EffectDirtyBits.EFFECT_DIRTY);
546 effectBoundsChanged();
547 }
548
549 @Override
550 public Object getBean() {
551 return InnerShadow.this;
552 }
553
554 @Override
555 public String getName() {
556 return "offsetX";
557 }
558 };
559 }
560 return offsetX;
561 }
562
563 /**
564 * The shadow offset in the y direction, in pixels.
565 * <pre>
566 * Min: n/a
567 * Max: n/a
568 * Default: 0.0
569 * Identity: 0.0
570 * </pre>
571 * @defaultValue 0.0
572 */
573 private DoubleProperty offsetY;
574
575
576 public final void setOffsetY(double value) {
577 offsetYProperty().set(value);
578 }
579
580 public final double getOffsetY() {
581 return offsetY == null ? 0 : offsetY.get();
582 }
583
584 public final DoubleProperty offsetYProperty() {
585 if (offsetY == null) {
586 offsetY = new DoublePropertyBase() {
587
588 @Override
589 public void invalidated() {
590 markDirty(EffectDirtyBits.EFFECT_DIRTY);
591 effectBoundsChanged();
592 }
593
594 @Override
595 public Object getBean() {
596 return InnerShadow.this;
597 }
598
599 @Override
600 public String getName() {
601 return "offsetY";
602 }
603 };
604 }
605 return offsetY;
606 }
607
608 private Color getColorInternal() {
609 Color c = getColor();
610 return c == null ? Color.BLACK : c;
611 }
612
613 private BlurType getBlurTypeInternal() {
614 BlurType bt = getBlurType();
615 return bt == null ? BlurType.THREE_PASS_BOX : bt;
616 }
617
618 @Override
619 void impl_update() {
620 Effect localInput = getInput();
621 if (localInput != null) {
622 localInput.impl_sync();
623 }
624
625 com.sun.scenario.effect.InnerShadow peer =
626 (com.sun.scenario.effect.InnerShadow) impl_getImpl();
627 peer.setShadowSourceInput(localInput == null ? null : localInput.impl_getImpl());
628 peer.setContentInput(localInput == null ? null : localInput.impl_getImpl());
629 peer.setGaussianWidth((float)Utils.clamp(0, getWidth(), 255));
630 peer.setGaussianHeight((float)Utils.clamp(0, getHeight(), 255));
631 peer.setShadowMode(Toolkit.getToolkit().toShadowMode(getBlurTypeInternal()));
632 peer.setColor(Toolkit.getToolkit().toColor4f(getColorInternal()));
633 peer.setChoke((float)Utils.clamp(0, getChoke(), 1));
634 peer.setOffsetX((int) getOffsetX());
635 peer.setOffsetY((int) getOffsetY());
636 }
637
638 /**
639 * @treatAsPrivate implementation detail
640 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
641 */
642 @Deprecated
643 @Override
644 public BaseBounds impl_getBounds(BaseBounds bounds,
645 BaseTransform tx,
646 Node node,
647 BoundsAccessor boundsAccessor) {
648 return getInputBounds(bounds, tx, node, boundsAccessor, getInput());
649 }
650
651 /**
652 * @treatAsPrivate implementation detail
653 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
654 */
655 @Deprecated
656 @Override
657 public Effect impl_copy() {
658 InnerShadow is = new InnerShadow(this.getBlurType(), this.getColor(),
659 this.getRadius(), this.getChoke(), this.getOffsetX(),
660 this.getOffsetY());
661 is.setInput(this.getInput());
662 is.setWidth(this.getWidth());
663 is.setHeight(this.getHeight());
664 return is;
665 }
666 }
--- EOF ---