mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-13 15:27:16 -06:00
FlatSVGIcon: getImage() now returns a multi-resolution image (on Java 9+) for HiDPI disabled icons in other LaFs that support multi-resolution images when producing disabled icons in LookAndFeel.getDisabledIcon() (e.g. Windows or Nimbus Laf) (issue #205)
This commit is contained in:
@@ -16,11 +16,20 @@
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
// This implementation is for Java 8 only.
|
||||
// There is also a variant for Java 9 and later.
|
||||
//
|
||||
// Make sure that the API is in sync.
|
||||
//
|
||||
|
||||
/**
|
||||
* Support for multi-resolution images available since Java 9.
|
||||
*
|
||||
@@ -28,26 +37,86 @@ import java.util.function.Function;
|
||||
*/
|
||||
public class MultiResolutionImageSupport
|
||||
{
|
||||
/**
|
||||
* Checks whether multi-resolution image support is available.
|
||||
*
|
||||
* @return {@code true} when running on Java 9 or later; {@code false} on Java 8
|
||||
*/
|
||||
public static boolean isAvailable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given image is a multi-resolution image that implements
|
||||
* the interface {@code java.awt.image.MultiResolutionImage}.
|
||||
*/
|
||||
public static boolean isMultiResolutionImage( Image image ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-resolution image from the given resolution variants.
|
||||
*
|
||||
* @param baseImageIndex index of the base image in the resolution variants array
|
||||
* @param resolutionVariants image resolution variants (sorted by size; smallest first)
|
||||
* @return a multi-resolution image on Java 9 or later; the base image on Java 8
|
||||
*/
|
||||
public static Image create( int baseImageIndex, Image... resolutionVariants ) {
|
||||
return resolutionVariants[baseImageIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-resolution image for the given dimensions.
|
||||
* Initially the image does not contain any image data.
|
||||
* The real images are created (and cached) on demand by invoking the given producer function.
|
||||
* <p>
|
||||
* The given dimensions array is only used for {@link #getResolutionVariants(Image)}.
|
||||
* The producer function may be invoked with any dimension (that is not contained in
|
||||
* dimensions array) and is expected to produce a image for the passed in dimension.
|
||||
*
|
||||
* @param baseImageIndex index of the base image in the dimensions array
|
||||
* @param dimensions dimensions of resolution variants (sorted by size; smallest first)
|
||||
* @param producer producer function that creates a real image for the requested size
|
||||
* @return a multi-resolution image on Java 9 or later; the base image on Java 8
|
||||
*/
|
||||
public static Image create( int baseImageIndex, Dimension[] dimensions, Function<Dimension, Image> producer ) {
|
||||
return producer.apply( dimensions[baseImageIndex] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a multi-resolution image that maps images from another multi-resolution image
|
||||
* using the given mapper function.
|
||||
* <p>
|
||||
* Can be used to apply filter to multi-resolution images on demand.
|
||||
* E.g. passed in image is for "enabled" state and mapper function creates images
|
||||
* for "disabled" state.
|
||||
*
|
||||
* @param image a multi-resolution image that is mapped using the given mapper function
|
||||
* @param mapper mapper function that maps a single resolution variant to a new image (e.g. applying an filter)
|
||||
* @return a multi-resolution image on Java 9 or later; a mapped image on Java 8
|
||||
*/
|
||||
public static Image map( Image image, Function<Image, Image> mapper ) {
|
||||
return mapper.apply( image );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image variant that best matches the given width and height.
|
||||
* <p>
|
||||
* If the given image is a multi-resolution image then invokes
|
||||
* {@code java.awt.image.MultiResolutionImage.getResolutionVariant(destImageWidth, destImageHeight)}.
|
||||
* Otherwise returns the given image.
|
||||
*/
|
||||
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all resolution variants.
|
||||
* <p>
|
||||
* If the given image is a multi-resolution image then invokes
|
||||
* {@code java.awt.image.MultiResolutionImage.getResolutionVariants()}.
|
||||
* Otherwise returns a list containing only the given image.
|
||||
*/
|
||||
public static List<Image> getResolutionVariants( Image image ) {
|
||||
return Collections.singletonList( image );
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.AbstractMultiResolutionImage;
|
||||
import java.awt.image.BaseMultiResolutionImage;
|
||||
@@ -27,6 +28,14 @@ import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
//
|
||||
// NOTE:
|
||||
// This implementation is for Java 9 and later.
|
||||
// There is also a variant for Java 8.
|
||||
//
|
||||
// Make sure that the API is in sync.
|
||||
//
|
||||
|
||||
/**
|
||||
* Support for multi-resolution images available since Java 9.
|
||||
*
|
||||
@@ -46,6 +55,10 @@ public class MultiResolutionImageSupport
|
||||
return new BaseMultiResolutionImage( baseImageIndex, resolutionVariants );
|
||||
}
|
||||
|
||||
public static Image create( int baseImageIndex, Dimension[] dimensions, Function<Dimension, Image> producer ) {
|
||||
return new ProducerMultiResolutionImage( dimensions, producer );
|
||||
}
|
||||
|
||||
public static Image map( Image image, Function<Image, Image> mapper ) {
|
||||
return image instanceof MultiResolutionImage
|
||||
? new MappedMultiResolutionImage( image, mapper )
|
||||
@@ -66,6 +79,9 @@ public class MultiResolutionImageSupport
|
||||
|
||||
//---- class MappedMultiResolutionImage -----------------------------------
|
||||
|
||||
/**
|
||||
* A multi-resolution image implementation that maps images on demand for requested sizes.
|
||||
*/
|
||||
private static class MappedMultiResolutionImage
|
||||
extends AbstractMultiResolutionImage
|
||||
{
|
||||
@@ -102,8 +118,52 @@ public class MultiResolutionImageSupport
|
||||
|
||||
private Image mapAndCacheImage( Image image ) {
|
||||
return cache.computeIfAbsent( image, img -> {
|
||||
// using ImageIcon here makes sure that the image is loaded
|
||||
return new ImageIcon( mapper.apply( img ) ).getImage();
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class ProducerMultiResolutionImage ---------------------------------
|
||||
|
||||
/**
|
||||
* A multi-resolution image implementation that produces images on demand for requested sizes.
|
||||
*/
|
||||
private static class ProducerMultiResolutionImage
|
||||
extends AbstractMultiResolutionImage
|
||||
{
|
||||
private final Dimension[] dimensions;
|
||||
private final Function<Dimension, Image> producer;
|
||||
private final IdentityHashMap<Dimension, Image> cache = new IdentityHashMap<>();
|
||||
|
||||
ProducerMultiResolutionImage( Dimension[] dimensions, Function<Dimension, Image> producer ) {
|
||||
this.dimensions = dimensions;
|
||||
this.producer = producer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image getResolutionVariant( double destImageWidth, double destImageHeight ) {
|
||||
return produceAndCacheImage( new Dimension( (int) destImageWidth, (int) destImageHeight ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Image> getResolutionVariants() {
|
||||
List<Image> mappedVariants = new ArrayList<>();
|
||||
for( Dimension size : dimensions )
|
||||
mappedVariants.add( produceAndCacheImage( size ) );
|
||||
return mappedVariants;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Image getBaseImage() {
|
||||
return produceAndCacheImage( dimensions[0] );
|
||||
}
|
||||
|
||||
private Image produceAndCacheImage( Dimension size ) {
|
||||
return cache.computeIfAbsent( size, size2 -> {
|
||||
// using ImageIcon here makes sure that the image is loaded
|
||||
return new ImageIcon( producer.apply( size2 ) ).getImage();
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user