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; 033import javafx.scene.paint.Color; 034 035import com.sun.javafx.Utils; 036import com.sun.javafx.effect.EffectDirtyBits; 037import com.sun.javafx.effect.EffectUtils; 038import com.sun.javafx.geom.BaseBounds; 039import com.sun.javafx.geom.transform.BaseTransform; 040import com.sun.javafx.scene.BoundsAccessor; 041import com.sun.javafx.tk.Toolkit; 042 043 044/** 045 * A high-level effect that renders a shadow inside the edges of the 046 * given content with the specified color, radius, and offset. 047 * 048 * <p> 049 * Example: 050 * <pre><code> 051 * InnerShadow innerShadow = new InnerShadow(); 052 * innerShadow.setOffsetX(4); 053 * innerShadow.setOffsetY(4); 054 * innerShadow.setColor(Color.web("0x3b596d")); 055 * 056 * Text text = new Text(); 057 * text.setEffect(innerShadow); 058 * text.setX(20); 059 * text.setY(100); 060 * text.setText("InnerShadow"); 061 * text.setFill(Color.ALICEBLUE); 062 * text.setFont(Font.font(null, FontWeight.BOLD, 50)); 063 * </pre></code> 064 * <p> The code above produces the following: </p> 065 * <p> 066 * <img * src="doc-files/innershadow.png"/> 067 * </p> 068 */ 069public class InnerShadow extends Effect { 070 private boolean changeIsLocal; 071 072 /** 073 * Creates a new instance of InnerShadow with default parameters. 074 */ 075 public InnerShadow() {} 076 077 /** 078 * Creates a new instance of InnerShadow with specified radius and color. 079 * @param radius the radius of the shadow blur kernel 080 * @param color the shadow {@code Color} 081 */ 082 public InnerShadow(double radius, Color color) { 083 setRadius(radius); 084 setColor(color); 085 } 086 087 /** 088 * Creates a new instance of InnerShadow with specified radius, offsetX, 089 * offsetY and color. 090 * @param radius the radius of the shadow blur kernel 091 * @param offsetX the shadow offset in the x direction 092 * @param offsetY the shadow offset in the y direction 093 * @param color the shadow {@code Color} 094 */ 095 public InnerShadow(double radius, double offsetX, double offsetY, Color color) { 096 setRadius(radius); 097 setOffsetX(offsetX); 098 setOffsetY(offsetY); 099 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 */ 113 public InnerShadow(BlurType blurType, Color color, double radius, double choke, 114 double offsetX, double offsetY) { 115 setBlurType(blurType); 116 setColor(color); 117 setRadius(radius); 118 setChoke(choke); 119 setOffsetX(offsetX); 120 setOffsetY(offsetY); 121 } 122 123 @Override 124 com.sun.scenario.effect.InnerShadow impl_createImpl() { 125 return new com.sun.scenario.effect.InnerShadow(); 126 }; 127 128 /** 129 * The input for this {@code Effect}. 130 * If set to {@code null}, or left unspecified, a graphical image of 131 * the {@code Node} to which the {@code Effect} is attached will be 132 * used as the input. 133 * @defaultValue null 134 * @since JavaFX 1.3 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 EffectUtils.getInputBounds(bounds, tx, 649 node, boundsAccessor, 650 getInput()); 651 } 652 653 /** 654 * 655 * @treatAsPrivate implementation detail 656 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 657 */ 658 @Deprecated 659 @Override 660 public Effect impl_copy() { 661 InnerShadow is = new InnerShadow(this.getBlurType(), this.getColor(), 662 this.getRadius(), this.getChoke(), this.getOffsetX(), 663 this.getOffsetY()); 664 is.setInput(this.getInput()); 665 is.setWidth(this.getWidth()); 666 is.setHeight(this.getHeight()); 667 return is; 668 } 669}