< prev index next >

modules/graphics/src/main/java/javafx/scene/image/ImageView.java

Print this page




 138  * <img src="doc-files/imageview.png"/>
 139  * </p>
 140  * @since JavaFX 2.0
 141  */
 142 @DefaultProperty("image")
 143 public class ImageView extends Node {
 144     static {
 145          // This is used by classes in different packages to get access to
 146          // private and package private methods.
 147         ImageViewHelper.setImageViewAccessor(new ImageViewHelper.ImageViewAccessor() {
 148             @Override
 149             public NGNode doCreatePeer(Node node) {
 150                 return ((ImageView) node).doCreatePeer();
 151             }
 152 
 153             @Override
 154             public void doUpdatePeer(Node node) {
 155                 ((ImageView) node).doUpdatePeer();
 156             }
 157 















 158         });
 159     }
 160 
 161     {
 162         // To initialize the class helper at the begining each constructor of this class
 163         ImageViewHelper.initHelper(this);
 164     }
 165     /**
 166      * Allocates a new ImageView object.
 167      */
 168     public ImageView() {
 169         getStyleClass().add(DEFAULT_STYLE_CLASS);
 170         setAccessibleRole(AccessibleRole.IMAGE_VIEW);
 171         setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
 172     }
 173 
 174     /**
 175      * Allocates a new ImageView object with image loaded from the specified
 176      * URL.
 177      * <p>


 225                 public void invalidated() {
 226                     Image _image = get();
 227                     boolean dimensionChanged = _image == null || oldImage == null ||
 228                                                 (oldImage.getWidth() != _image.getWidth() ||
 229                                                 oldImage.getHeight() != _image.getHeight());
 230 
 231                     if (needsListeners) {
 232                         Toolkit.getImageAccessor().getImageProperty(oldImage).
 233                                 removeListener(platformImageChangeListener.getWeakListener());
 234                     }
 235 
 236                     needsListeners = _image != null && (_image.isAnimation() || _image.getProgress() < 1);
 237                     oldImage = _image;
 238 
 239                     if (needsListeners) {
 240                         Toolkit.getImageAccessor().getImageProperty(_image).
 241                                 addListener(platformImageChangeListener.getWeakListener());
 242                     }
 243                     if (dimensionChanged) {
 244                         invalidateWidthHeight();
 245                         impl_geomChanged();
 246                     }
 247                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_CONTENTS);
 248                 }
 249 
 250                 @Override
 251                 public Object getBean() {
 252                     return ImageView.this;
 253                 }
 254 
 255                 @Override
 256                 public String getName() {
 257                     return "image";
 258                 }
 259             };
 260         }
 261         return image;
 262     }
 263 
 264     private StringProperty imageUrl = null;
 265     /**


 291                 public String getName() {
 292                     return "imageUrl";
 293                 }
 294 
 295                 @Override
 296                 public CssMetaData<ImageView,String> getCssMetaData() {
 297                     return StyleableProperties.IMAGE;
 298                 }
 299 
 300             };
 301         }
 302         return imageUrl;
 303     }
 304 
 305     private final AbstractNotifyListener platformImageChangeListener =
 306             new AbstractNotifyListener() {
 307         @Override
 308         public void invalidated(Observable valueModel) {
 309             invalidateWidthHeight();
 310             NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_CONTENTS);
 311             impl_geomChanged();
 312         }
 313     };
 314     /**
 315      * The current x coordinate of the {@code ImageView} origin.
 316      *
 317      * @defaultValue 0
 318      */
 319     private DoubleProperty x;
 320 
 321 
 322     public final void setX(double value) {
 323         xProperty().set(value);
 324     }
 325 
 326     public final double getX() {
 327         return x == null ? 0.0 : x.get();
 328     }
 329 
 330     public final DoubleProperty xProperty() {
 331         if (x == null) {
 332             x = new DoublePropertyBase() {
 333 
 334                 @Override
 335                 protected void invalidated() {
 336                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_GEOMETRY);
 337                     impl_geomChanged();
 338                 }
 339 
 340                 @Override
 341                 public Object getBean() {
 342                     return ImageView.this;
 343                 }
 344 
 345                 @Override
 346                 public String getName() {
 347                     return "x";
 348                 }
 349             };
 350         }
 351         return x;
 352     }
 353 
 354     /**
 355      * The current y coordinate of the {@code ImageView} origin.
 356      *
 357      * @defaultValue 0
 358      */
 359     private DoubleProperty y;
 360 
 361 
 362     public final void setY(double value) {
 363         yProperty().set(value);
 364     }
 365 
 366     public final double getY() {
 367         return y == null ? 0.0 : y.get();
 368     }
 369 
 370     public final DoubleProperty yProperty() {
 371         if (y == null) {
 372             y = new DoublePropertyBase() {
 373 
 374                 @Override
 375                 protected void invalidated() {
 376                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_GEOMETRY);
 377                     impl_geomChanged();
 378                 }
 379 
 380                 @Override
 381                 public Object getBean() {
 382                     return ImageView.this;
 383                 }
 384 
 385                 @Override
 386                 public String getName() {
 387                     return "y";
 388                 }
 389             };
 390         }
 391         return y;
 392     }
 393 
 394     /**
 395      * The width of the bounding box within which the source image is resized as
 396      * necessary to fit. If set to a value <= 0, then the intrinsic width of the
 397      * image will be used as the {@code fitWidth}.


 404      */
 405     private DoubleProperty fitWidth;
 406 
 407 
 408     public final void setFitWidth(double value) {
 409         fitWidthProperty().set(value);
 410     }
 411 
 412     public final double getFitWidth() {
 413         return fitWidth == null ? 0.0 : fitWidth.get();
 414     }
 415 
 416     public final DoubleProperty fitWidthProperty() {
 417         if (fitWidth == null) {
 418             fitWidth = new DoublePropertyBase() {
 419 
 420                 @Override
 421                 protected void invalidated() {
 422                     invalidateWidthHeight();
 423                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
 424                     impl_geomChanged();
 425                 }
 426 
 427                 @Override
 428                 public Object getBean() {
 429                     return ImageView.this;
 430                 }
 431 
 432                 @Override
 433                 public String getName() {
 434                     return "fitWidth";
 435                 }
 436             };
 437         }
 438         return fitWidth;
 439     }
 440 
 441     /**
 442      * The height of the bounding box within which the source image is resized
 443      * as necessary to fit. If set to a value <= 0, then the intrinsic height of
 444      * the image will be used as the {@code fitHeight}.


 452      */
 453     private DoubleProperty fitHeight;
 454 
 455 
 456     public final void setFitHeight(double value) {
 457         fitHeightProperty().set(value);
 458     }
 459 
 460     public final double getFitHeight() {
 461         return fitHeight == null ? 0.0 : fitHeight.get();
 462     }
 463 
 464     public final DoubleProperty fitHeightProperty() {
 465         if (fitHeight == null) {
 466             fitHeight = new DoublePropertyBase() {
 467 
 468                 @Override
 469                 protected void invalidated() {
 470                     invalidateWidthHeight();
 471                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
 472                     impl_geomChanged();
 473                 }
 474 
 475                 @Override
 476                 public Object getBean() {
 477                     return ImageView.this;
 478                 }
 479 
 480                 @Override
 481                 public String getName() {
 482                     return "fitHeight";
 483                 }
 484             };
 485         }
 486         return fitHeight;
 487     }
 488 
 489     /**
 490      * Indicates whether to preserve the aspect ratio of the source image when
 491      * scaling to fit the image within the fitting bounding box.
 492      * <p/>


 517      */
 518     private BooleanProperty preserveRatio;
 519 
 520 
 521     public final void setPreserveRatio(boolean value) {
 522         preserveRatioProperty().set(value);
 523     }
 524 
 525     public final boolean isPreserveRatio() {
 526         return preserveRatio == null ? false : preserveRatio.get();
 527     }
 528 
 529     public final BooleanProperty preserveRatioProperty() {
 530         if (preserveRatio == null) {
 531             preserveRatio = new BooleanPropertyBase() {
 532 
 533                 @Override
 534                 protected void invalidated() {
 535                     invalidateWidthHeight();
 536                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
 537                     impl_geomChanged();
 538                 }
 539 
 540                 @Override
 541                 public Object getBean() {
 542                     return ImageView.this;
 543                 }
 544 
 545                 @Override
 546                 public String getName() {
 547                     return "preserveRatio";
 548                 }
 549             };
 550         }
 551         return preserveRatio;
 552     }
 553 
 554     /**
 555      * Indicates whether to use a better quality filtering algorithm or a faster
 556      * one when transforming or scaling the source image to fit within the
 557      * bounding box provided by {@code fitWidth} and {@code fitHeight}.


 621      */
 622     private ObjectProperty<Rectangle2D> viewport;
 623 
 624 
 625     public final void setViewport(Rectangle2D value) {
 626         viewportProperty().set(value);
 627     }
 628 
 629     public final Rectangle2D getViewport() {
 630         return viewport == null ? null : viewport.get();
 631     }
 632 
 633     public final ObjectProperty<Rectangle2D> viewportProperty() {
 634         if (viewport == null) {
 635             viewport = new ObjectPropertyBase<Rectangle2D>() {
 636 
 637                 @Override
 638                 protected void invalidated() {
 639                     invalidateWidthHeight();
 640                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
 641                     impl_geomChanged();
 642                 }
 643 
 644                 @Override
 645                 public Object getBean() {
 646                     return ImageView.this;
 647                 }
 648 
 649                 @Override
 650                 public String getName() {
 651                     return "viewport";
 652                 }
 653             };
 654         }
 655         return viewport;
 656     }
 657 
 658     // Need to track changes to image width and image height and recompute
 659     // bounds when changed.
 660     // imageWidth = bind image.width on replace {
 661     // impl_geomChanged();
 662     // }
 663     //
 664     // imageHeight = bind image.height on replace {
 665     // impl_geomChanged();
 666     // }
 667 
 668     private double destWidth, destHeight;
 669 
 670     /*
 671      * Note: This method MUST only be called via its accessor method.
 672      */
 673     private NGNode doCreatePeer() {
 674         return new NGImageView();
 675     }
 676 
 677     /**
 678      * @treatAsPrivate implementation detail
 679      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 680      */
 681     @Deprecated
 682     @Override public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) {
 683         recomputeWidthHeight();
 684 
 685         bounds = bounds.deriveWithNewBounds((float)getX(), (float)getY(), 0.0f,
 686                 (float)(getX() + destWidth), (float)(getY() + destHeight), 0.0f);
 687         bounds = tx.transform(bounds, bounds);
 688         return bounds;
 689     }
 690 
 691     private boolean validWH;
 692 
 693     private void invalidateWidthHeight() {
 694         validWH = false;
 695     }
 696 
 697     private void recomputeWidthHeight() {
 698         if (validWH) {
 699             return;
 700         }
 701         Image localImage = getImage();
 702         Rectangle2D localViewport = getViewport();


 714         double localFitWidth = getFitWidth();
 715         double localFitHeight = getFitHeight();
 716 
 717         if (isPreserveRatio() && w > 0 && h > 0 && (localFitWidth > 0 || localFitHeight > 0)) {
 718             if (localFitWidth <= 0 || (localFitHeight > 0 && localFitWidth * h > localFitHeight * w)) {
 719                 w = w * localFitHeight / h;
 720                 h = localFitHeight;
 721             } else {
 722                 h = h * localFitWidth / w;
 723                 w = localFitWidth;
 724             }
 725         } else {
 726             if (localFitWidth > 0f) {
 727                 w = localFitWidth;
 728             }
 729             if (localFitHeight > 0f) {
 730                 h = localFitHeight;
 731             }
 732         }
 733 
 734         // Store these values for use later in impl_computeContains() to support
 735         // Node.contains().
 736         destWidth = w;
 737         destHeight = h;
 738 
 739         validWH = true;
 740     }
 741 
 742     /**
 743      * @treatAsPrivate implementation detail
 744      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 745      */
 746     @Deprecated
 747     @Override protected boolean impl_computeContains(double localX, double localY) {
 748         if (getImage() == null) {
 749             return false;
 750         }
 751 
 752         recomputeWidthHeight();
 753         // Local Note bounds contain test is already done by the caller.
 754         // (Node.contains()).
 755 
 756         double dx = localX - getX();
 757         double dy = localY - getY();
 758 
 759         Image localImage = getImage();
 760         double srcWidth = localImage.getWidth();
 761         double srcHeight = localImage.getHeight();
 762         double viewWidth = srcWidth;
 763         double viewHeight = srcHeight;
 764         double vw = 0;
 765         double vh = 0;
 766         double vminx = 0;
 767         double vminy = 0;
 768         Rectangle2D localViewport = getViewport();
 769         if (localViewport != null) {
 770             vw = localViewport.getWidth();
 771             vh = localViewport.getHeight();
 772             vminx = localViewport.getMinX();
 773             vminy = localViewport.getMinY();
 774         }
 775 
 776         if (vw > 0 && vh > 0) {
 777             viewWidth = vw;
 778             viewHeight = vh;
 779         }
 780 
 781         // desWidth Note and destHeight are computed by impl_computeGeomBounds()
 782         // via a call from Node.contains() before calling
 783         // impl_computeContains().
 784         // Transform into image's coordinate system.
 785         dx = vminx + dx * viewWidth / destWidth;
 786         dy = vminy + dy * viewHeight / destHeight;
 787         // test whether it's inside the original image AND inside of viewport
 788         // (viewport may stick out from the image bounds)
 789         if (dx < 0.0 || dy < 0.0 || dx >= srcWidth || dy >= srcHeight ||
 790                 dx < vminx || dy < vminy ||
 791                 dx >= vminx + viewWidth || dy >= vminy + viewHeight) {
 792             return false;
 793         }
 794         // Do alpha test on the picked pixel.
 795         return Toolkit.getToolkit().imageContains(
 796                 Toolkit.getImageAccessor().getPlatformImage(localImage), (float)dx, (float)dy);
 797     }
 798 
 799     /***************************************************************************
 800      * * Stylesheet Handling * *
 801      **************************************************************************/
 802 
 803     private static final String DEFAULT_STYLE_CLASS = "image-view";


 876      */
 877     private void doUpdatePeer() {
 878         final NGImageView peer = NodeHelper.getPeer(this);
 879         if (NodeHelper.isDirty(this, DirtyBits.NODE_GEOMETRY)) {
 880             peer.setX((float)getX());
 881             peer.setY((float)getY());
 882         }
 883         if (NodeHelper.isDirty(this, DirtyBits.NODE_SMOOTH)) {
 884             peer.setSmooth(isSmooth());
 885         }
 886         if (NodeHelper.isDirty(this, DirtyBits.NODE_CONTENTS)) {
 887             peer.setImage(getImage() != null
 888                     ? Toolkit.getImageAccessor().getPlatformImage(getImage()) : null);
 889         }
 890         // The NG part expects this to be called when image changes
 891         if (NodeHelper.isDirty(this, DirtyBits.NODE_VIEWPORT) || NodeHelper.isDirty(this, DirtyBits.NODE_CONTENTS)) {
 892             updateViewport();
 893         }
 894     }
 895 
 896     /**
 897      * @treatAsPrivate implementation detail
 898      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
 899      */
 900     @Deprecated
 901     @Override public Object impl_processMXNode(MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
 902         return alg.processLeafNode(this, ctx);
 903     }
 904 }


 138  * <img src="doc-files/imageview.png"/>
 139  * </p>
 140  * @since JavaFX 2.0
 141  */
 142 @DefaultProperty("image")
 143 public class ImageView extends Node {
 144     static {
 145          // This is used by classes in different packages to get access to
 146          // private and package private methods.
 147         ImageViewHelper.setImageViewAccessor(new ImageViewHelper.ImageViewAccessor() {
 148             @Override
 149             public NGNode doCreatePeer(Node node) {
 150                 return ((ImageView) node).doCreatePeer();
 151             }
 152 
 153             @Override
 154             public void doUpdatePeer(Node node) {
 155                 ((ImageView) node).doUpdatePeer();
 156             }
 157 
 158             @Override
 159             public BaseBounds doComputeGeomBounds(Node node,
 160             BaseBounds bounds, BaseTransform tx) {
 161                 return ((ImageView) node).doComputeGeomBounds(bounds, tx);
 162             }
 163 
 164             @Override
 165             public boolean doComputeContains(Node node, double localX, double localY) {
 166                 return ((ImageView) node).doComputeContains(localX, localY);
 167             }
 168 
 169             @Override
 170             public Object doProcessMXNode(Node node, MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
 171                 return ((ImageView) node).doProcessMXNode(alg, ctx);
 172             }
 173         });
 174     }
 175 
 176     {
 177         // To initialize the class helper at the begining each constructor of this class
 178         ImageViewHelper.initHelper(this);
 179     }
 180     /**
 181      * Allocates a new ImageView object.
 182      */
 183     public ImageView() {
 184         getStyleClass().add(DEFAULT_STYLE_CLASS);
 185         setAccessibleRole(AccessibleRole.IMAGE_VIEW);
 186         setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
 187     }
 188 
 189     /**
 190      * Allocates a new ImageView object with image loaded from the specified
 191      * URL.
 192      * <p>


 240                 public void invalidated() {
 241                     Image _image = get();
 242                     boolean dimensionChanged = _image == null || oldImage == null ||
 243                                                 (oldImage.getWidth() != _image.getWidth() ||
 244                                                 oldImage.getHeight() != _image.getHeight());
 245 
 246                     if (needsListeners) {
 247                         Toolkit.getImageAccessor().getImageProperty(oldImage).
 248                                 removeListener(platformImageChangeListener.getWeakListener());
 249                     }
 250 
 251                     needsListeners = _image != null && (_image.isAnimation() || _image.getProgress() < 1);
 252                     oldImage = _image;
 253 
 254                     if (needsListeners) {
 255                         Toolkit.getImageAccessor().getImageProperty(_image).
 256                                 addListener(platformImageChangeListener.getWeakListener());
 257                     }
 258                     if (dimensionChanged) {
 259                         invalidateWidthHeight();
 260                         NodeHelper.geomChanged(ImageView.this);
 261                     }
 262                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_CONTENTS);
 263                 }
 264 
 265                 @Override
 266                 public Object getBean() {
 267                     return ImageView.this;
 268                 }
 269 
 270                 @Override
 271                 public String getName() {
 272                     return "image";
 273                 }
 274             };
 275         }
 276         return image;
 277     }
 278 
 279     private StringProperty imageUrl = null;
 280     /**


 306                 public String getName() {
 307                     return "imageUrl";
 308                 }
 309 
 310                 @Override
 311                 public CssMetaData<ImageView,String> getCssMetaData() {
 312                     return StyleableProperties.IMAGE;
 313                 }
 314 
 315             };
 316         }
 317         return imageUrl;
 318     }
 319 
 320     private final AbstractNotifyListener platformImageChangeListener =
 321             new AbstractNotifyListener() {
 322         @Override
 323         public void invalidated(Observable valueModel) {
 324             invalidateWidthHeight();
 325             NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_CONTENTS);
 326             NodeHelper.geomChanged(ImageView.this);
 327         }
 328     };
 329     /**
 330      * The current x coordinate of the {@code ImageView} origin.
 331      *
 332      * @defaultValue 0
 333      */
 334     private DoubleProperty x;
 335 
 336 
 337     public final void setX(double value) {
 338         xProperty().set(value);
 339     }
 340 
 341     public final double getX() {
 342         return x == null ? 0.0 : x.get();
 343     }
 344 
 345     public final DoubleProperty xProperty() {
 346         if (x == null) {
 347             x = new DoublePropertyBase() {
 348 
 349                 @Override
 350                 protected void invalidated() {
 351                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_GEOMETRY);
 352                     NodeHelper.geomChanged(ImageView.this);
 353                 }
 354 
 355                 @Override
 356                 public Object getBean() {
 357                     return ImageView.this;
 358                 }
 359 
 360                 @Override
 361                 public String getName() {
 362                     return "x";
 363                 }
 364             };
 365         }
 366         return x;
 367     }
 368 
 369     /**
 370      * The current y coordinate of the {@code ImageView} origin.
 371      *
 372      * @defaultValue 0
 373      */
 374     private DoubleProperty y;
 375 
 376 
 377     public final void setY(double value) {
 378         yProperty().set(value);
 379     }
 380 
 381     public final double getY() {
 382         return y == null ? 0.0 : y.get();
 383     }
 384 
 385     public final DoubleProperty yProperty() {
 386         if (y == null) {
 387             y = new DoublePropertyBase() {
 388 
 389                 @Override
 390                 protected void invalidated() {
 391                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_GEOMETRY);
 392                     NodeHelper.geomChanged(ImageView.this);
 393                 }
 394 
 395                 @Override
 396                 public Object getBean() {
 397                     return ImageView.this;
 398                 }
 399 
 400                 @Override
 401                 public String getName() {
 402                     return "y";
 403                 }
 404             };
 405         }
 406         return y;
 407     }
 408 
 409     /**
 410      * The width of the bounding box within which the source image is resized as
 411      * necessary to fit. If set to a value <= 0, then the intrinsic width of the
 412      * image will be used as the {@code fitWidth}.


 419      */
 420     private DoubleProperty fitWidth;
 421 
 422 
 423     public final void setFitWidth(double value) {
 424         fitWidthProperty().set(value);
 425     }
 426 
 427     public final double getFitWidth() {
 428         return fitWidth == null ? 0.0 : fitWidth.get();
 429     }
 430 
 431     public final DoubleProperty fitWidthProperty() {
 432         if (fitWidth == null) {
 433             fitWidth = new DoublePropertyBase() {
 434 
 435                 @Override
 436                 protected void invalidated() {
 437                     invalidateWidthHeight();
 438                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
 439                     NodeHelper.geomChanged(ImageView.this);
 440                 }
 441 
 442                 @Override
 443                 public Object getBean() {
 444                     return ImageView.this;
 445                 }
 446 
 447                 @Override
 448                 public String getName() {
 449                     return "fitWidth";
 450                 }
 451             };
 452         }
 453         return fitWidth;
 454     }
 455 
 456     /**
 457      * The height of the bounding box within which the source image is resized
 458      * as necessary to fit. If set to a value <= 0, then the intrinsic height of
 459      * the image will be used as the {@code fitHeight}.


 467      */
 468     private DoubleProperty fitHeight;
 469 
 470 
 471     public final void setFitHeight(double value) {
 472         fitHeightProperty().set(value);
 473     }
 474 
 475     public final double getFitHeight() {
 476         return fitHeight == null ? 0.0 : fitHeight.get();
 477     }
 478 
 479     public final DoubleProperty fitHeightProperty() {
 480         if (fitHeight == null) {
 481             fitHeight = new DoublePropertyBase() {
 482 
 483                 @Override
 484                 protected void invalidated() {
 485                     invalidateWidthHeight();
 486                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
 487                     NodeHelper.geomChanged(ImageView.this);
 488                 }
 489 
 490                 @Override
 491                 public Object getBean() {
 492                     return ImageView.this;
 493                 }
 494 
 495                 @Override
 496                 public String getName() {
 497                     return "fitHeight";
 498                 }
 499             };
 500         }
 501         return fitHeight;
 502     }
 503 
 504     /**
 505      * Indicates whether to preserve the aspect ratio of the source image when
 506      * scaling to fit the image within the fitting bounding box.
 507      * <p/>


 532      */
 533     private BooleanProperty preserveRatio;
 534 
 535 
 536     public final void setPreserveRatio(boolean value) {
 537         preserveRatioProperty().set(value);
 538     }
 539 
 540     public final boolean isPreserveRatio() {
 541         return preserveRatio == null ? false : preserveRatio.get();
 542     }
 543 
 544     public final BooleanProperty preserveRatioProperty() {
 545         if (preserveRatio == null) {
 546             preserveRatio = new BooleanPropertyBase() {
 547 
 548                 @Override
 549                 protected void invalidated() {
 550                     invalidateWidthHeight();
 551                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
 552                     NodeHelper.geomChanged(ImageView.this);
 553                 }
 554 
 555                 @Override
 556                 public Object getBean() {
 557                     return ImageView.this;
 558                 }
 559 
 560                 @Override
 561                 public String getName() {
 562                     return "preserveRatio";
 563                 }
 564             };
 565         }
 566         return preserveRatio;
 567     }
 568 
 569     /**
 570      * Indicates whether to use a better quality filtering algorithm or a faster
 571      * one when transforming or scaling the source image to fit within the
 572      * bounding box provided by {@code fitWidth} and {@code fitHeight}.


 636      */
 637     private ObjectProperty<Rectangle2D> viewport;
 638 
 639 
 640     public final void setViewport(Rectangle2D value) {
 641         viewportProperty().set(value);
 642     }
 643 
 644     public final Rectangle2D getViewport() {
 645         return viewport == null ? null : viewport.get();
 646     }
 647 
 648     public final ObjectProperty<Rectangle2D> viewportProperty() {
 649         if (viewport == null) {
 650             viewport = new ObjectPropertyBase<Rectangle2D>() {
 651 
 652                 @Override
 653                 protected void invalidated() {
 654                     invalidateWidthHeight();
 655                     NodeHelper.markDirty(ImageView.this, DirtyBits.NODE_VIEWPORT);
 656                     NodeHelper.geomChanged(ImageView.this);
 657                 }
 658 
 659                 @Override
 660                 public Object getBean() {
 661                     return ImageView.this;
 662                 }
 663 
 664                 @Override
 665                 public String getName() {
 666                     return "viewport";
 667                 }
 668             };
 669         }
 670         return viewport;
 671     }
 672 
 673     // Need to track changes to image width and image height and recompute
 674     // bounds when changed.
 675     // imageWidth = bind image.width on replace {
 676     // NodeHelper.geomChanged(ImageView.this);
 677     // }
 678     //
 679     // imageHeight = bind image.height on replace {
 680     // NodeHelper.geomChanged(ImageView.this);
 681     // }
 682 
 683     private double destWidth, destHeight;
 684 
 685     /*
 686      * Note: This method MUST only be called via its accessor method.
 687      */
 688     private NGNode doCreatePeer() {
 689         return new NGImageView();
 690     }
 691 
 692     /*
 693      * Note: This method MUST only be called via its accessor method.

 694      */
 695     private BaseBounds doComputeGeomBounds(BaseBounds bounds, BaseTransform tx) {

 696         recomputeWidthHeight();
 697 
 698         bounds = bounds.deriveWithNewBounds((float)getX(), (float)getY(), 0.0f,
 699                 (float)(getX() + destWidth), (float)(getY() + destHeight), 0.0f);
 700         bounds = tx.transform(bounds, bounds);
 701         return bounds;
 702     }
 703 
 704     private boolean validWH;
 705 
 706     private void invalidateWidthHeight() {
 707         validWH = false;
 708     }
 709 
 710     private void recomputeWidthHeight() {
 711         if (validWH) {
 712             return;
 713         }
 714         Image localImage = getImage();
 715         Rectangle2D localViewport = getViewport();


 727         double localFitWidth = getFitWidth();
 728         double localFitHeight = getFitHeight();
 729 
 730         if (isPreserveRatio() && w > 0 && h > 0 && (localFitWidth > 0 || localFitHeight > 0)) {
 731             if (localFitWidth <= 0 || (localFitHeight > 0 && localFitWidth * h > localFitHeight * w)) {
 732                 w = w * localFitHeight / h;
 733                 h = localFitHeight;
 734             } else {
 735                 h = h * localFitWidth / w;
 736                 w = localFitWidth;
 737             }
 738         } else {
 739             if (localFitWidth > 0f) {
 740                 w = localFitWidth;
 741             }
 742             if (localFitHeight > 0f) {
 743                 h = localFitHeight;
 744             }
 745         }
 746 
 747         // Store these values for use later in doComputeContains() to support
 748         // Node.contains().
 749         destWidth = w;
 750         destHeight = h;
 751 
 752         validWH = true;
 753     }
 754 
 755     /*
 756      * Note: This method MUST only be called via its accessor method.

 757      */
 758     private boolean doComputeContains(double localX, double localY) {

 759         if (getImage() == null) {
 760             return false;
 761         }
 762 
 763         recomputeWidthHeight();
 764         // Local Note bounds contain test is already done by the caller.
 765         // (Node.contains()).
 766 
 767         double dx = localX - getX();
 768         double dy = localY - getY();
 769 
 770         Image localImage = getImage();
 771         double srcWidth = localImage.getWidth();
 772         double srcHeight = localImage.getHeight();
 773         double viewWidth = srcWidth;
 774         double viewHeight = srcHeight;
 775         double vw = 0;
 776         double vh = 0;
 777         double vminx = 0;
 778         double vminy = 0;
 779         Rectangle2D localViewport = getViewport();
 780         if (localViewport != null) {
 781             vw = localViewport.getWidth();
 782             vh = localViewport.getHeight();
 783             vminx = localViewport.getMinX();
 784             vminy = localViewport.getMinY();
 785         }
 786 
 787         if (vw > 0 && vh > 0) {
 788             viewWidth = vw;
 789             viewHeight = vh;
 790         }
 791 
 792         // desWidth Note and destHeight are computed by NodeHelper.computeGeomBounds()
 793         // via a call from Node.contains() before calling
 794         // doComputeContains().
 795         // Transform into image's coordinate system.
 796         dx = vminx + dx * viewWidth / destWidth;
 797         dy = vminy + dy * viewHeight / destHeight;
 798         // test whether it's inside the original image AND inside of viewport
 799         // (viewport may stick out from the image bounds)
 800         if (dx < 0.0 || dy < 0.0 || dx >= srcWidth || dy >= srcHeight ||
 801                 dx < vminx || dy < vminy ||
 802                 dx >= vminx + viewWidth || dy >= vminy + viewHeight) {
 803             return false;
 804         }
 805         // Do alpha test on the picked pixel.
 806         return Toolkit.getToolkit().imageContains(
 807                 Toolkit.getImageAccessor().getPlatformImage(localImage), (float)dx, (float)dy);
 808     }
 809 
 810     /***************************************************************************
 811      * * Stylesheet Handling * *
 812      **************************************************************************/
 813 
 814     private static final String DEFAULT_STYLE_CLASS = "image-view";


 887      */
 888     private void doUpdatePeer() {
 889         final NGImageView peer = NodeHelper.getPeer(this);
 890         if (NodeHelper.isDirty(this, DirtyBits.NODE_GEOMETRY)) {
 891             peer.setX((float)getX());
 892             peer.setY((float)getY());
 893         }
 894         if (NodeHelper.isDirty(this, DirtyBits.NODE_SMOOTH)) {
 895             peer.setSmooth(isSmooth());
 896         }
 897         if (NodeHelper.isDirty(this, DirtyBits.NODE_CONTENTS)) {
 898             peer.setImage(getImage() != null
 899                     ? Toolkit.getImageAccessor().getPlatformImage(getImage()) : null);
 900         }
 901         // The NG part expects this to be called when image changes
 902         if (NodeHelper.isDirty(this, DirtyBits.NODE_VIEWPORT) || NodeHelper.isDirty(this, DirtyBits.NODE_CONTENTS)) {
 903             updateViewport();
 904         }
 905     }
 906 
 907     /*
 908      * Note: This method MUST only be called via its accessor method.

 909      */
 910     private Object doProcessMXNode(MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {

 911         return alg.processLeafNode(this, ctx);
 912     }
 913 }
< prev index next >