mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-13 23:37:13 -06:00
FileChooser: scale file icons (issue #100)
This commit is contained in:
@@ -19,11 +19,13 @@ package com.formdev.flatlaf.ui;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JFileChooser;
|
import javax.swing.JFileChooser;
|
||||||
import javax.swing.filechooser.FileView;
|
import javax.swing.filechooser.FileView;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.metal.MetalFileChooserUI;
|
import javax.swing.plaf.metal.MetalFileChooserUI;
|
||||||
|
import com.formdev.flatlaf.util.ScaledImageIcon;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -157,19 +159,32 @@ public class FlatFileChooserUI
|
|||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public Icon getIcon( File f ) {
|
public Icon getIcon( File f ) {
|
||||||
|
// get cached icon
|
||||||
Icon icon = getCachedIcon( f );
|
Icon icon = getCachedIcon( f );
|
||||||
if( icon != null )
|
if( icon != null )
|
||||||
return icon;
|
return icon;
|
||||||
|
|
||||||
|
// get system icon
|
||||||
if( f != null ) {
|
if( f != null ) {
|
||||||
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
icon = getFileChooser().getFileSystemView().getSystemIcon( f );
|
||||||
|
|
||||||
if( icon != null ) {
|
if( icon != null ) {
|
||||||
|
if( icon instanceof ImageIcon )
|
||||||
|
icon = new ScaledImageIcon( (ImageIcon) icon );
|
||||||
cacheIcon( f, icon );
|
cacheIcon( f, icon );
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getIcon( f );
|
// get default icon
|
||||||
|
icon = super.getIcon( f );
|
||||||
|
|
||||||
|
if( icon instanceof ImageIcon ) {
|
||||||
|
icon = new ScaledImageIcon( (ImageIcon) icon );
|
||||||
|
cacheIcon( f, icon );
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
package com.formdev.flatlaf.util;
|
package com.formdev.flatlaf.util;
|
||||||
|
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,4 +43,12 @@ public class MultiResolutionImageSupport
|
|||||||
public static Image map( Image image, Function<Image, Image> mapper ) {
|
public static Image map( Image image, Function<Image, Image> mapper ) {
|
||||||
return mapper.apply( image );
|
return mapper.apply( image );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Image> getResolutionVariants( Image image ) {
|
||||||
|
return Collections.singletonList( image );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.util;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales the given image icon using the system and user scale factors and
|
||||||
|
* paints the icon at system scale factor 1x. This gives best scaling quality.
|
||||||
|
* If the given image icon supports multiple resolutions, the best resolution
|
||||||
|
* variant is used. The last scaled image is cached for faster repainting.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class ScaledImageIcon
|
||||||
|
implements Icon
|
||||||
|
{
|
||||||
|
private final ImageIcon imageIcon;
|
||||||
|
|
||||||
|
private double lastSystemScaleFactor;
|
||||||
|
private float lastUserScaleFactor;
|
||||||
|
private Image lastImage;
|
||||||
|
|
||||||
|
public ScaledImageIcon( ImageIcon imageIcon ) {
|
||||||
|
this.imageIcon = imageIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconWidth() {
|
||||||
|
return UIScale.scale( imageIcon.getIconWidth() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIconHeight() {
|
||||||
|
return UIScale.scale( imageIcon.getIconHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintIcon( Component c, Graphics g, int x, int y ) {
|
||||||
|
/*debug
|
||||||
|
g.setColor( Color.red );
|
||||||
|
g.drawRect( x, y, getIconWidth(), getIconHeight() );
|
||||||
|
debug*/
|
||||||
|
|
||||||
|
// scale factor
|
||||||
|
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
|
||||||
|
float userScaleFactor = UIScale.getUserScaleFactor();
|
||||||
|
double scaleFactor = systemScaleFactor * userScaleFactor;
|
||||||
|
|
||||||
|
// paint input image icon if not necessary to scale
|
||||||
|
if( scaleFactor == 1 ) {
|
||||||
|
imageIcon.paintIcon( c, g, x, y );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// paint cached scaled icon
|
||||||
|
if( systemScaleFactor == lastSystemScaleFactor &&
|
||||||
|
userScaleFactor == lastUserScaleFactor &&
|
||||||
|
lastImage != null )
|
||||||
|
{
|
||||||
|
paintLastImage( g, x, y );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// destination image size
|
||||||
|
int destImageWidth = (int) Math.round( imageIcon.getIconWidth() * scaleFactor );
|
||||||
|
int destImageHeight = (int) Math.round( imageIcon.getIconHeight() * scaleFactor );
|
||||||
|
|
||||||
|
// get resolution variant of image if it is a multi-resolution image
|
||||||
|
Image image = MultiResolutionImageSupport.getResolutionVariant(
|
||||||
|
imageIcon.getImage(), destImageWidth, destImageHeight );
|
||||||
|
|
||||||
|
// size of image
|
||||||
|
int imageWidth = image.getWidth( null );
|
||||||
|
int imageHeight = image.getHeight( null );
|
||||||
|
|
||||||
|
// scale image if necessary to destination size
|
||||||
|
if( imageWidth != destImageWidth || imageHeight != destImageHeight ) {
|
||||||
|
// determine scaling method; default is "quality"
|
||||||
|
Object scalingInterpolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
|
||||||
|
float imageScaleFactor = (float) destImageWidth / (float) imageWidth;
|
||||||
|
if( ((int) imageScaleFactor) == imageScaleFactor &&
|
||||||
|
imageScaleFactor > 1f &&
|
||||||
|
imageWidth <= 16 &&
|
||||||
|
imageHeight <= 16 )
|
||||||
|
{
|
||||||
|
// use "speed" scaling for small icons if the scale factor is an integer
|
||||||
|
// to avoid blurred icons
|
||||||
|
scalingInterpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale image
|
||||||
|
BufferedImage bufferedImage = image2bufferedImage( image );
|
||||||
|
image = scaleImage( bufferedImage, destImageWidth, destImageHeight, scalingInterpolation );
|
||||||
|
}
|
||||||
|
|
||||||
|
// cache image
|
||||||
|
lastSystemScaleFactor = systemScaleFactor;
|
||||||
|
lastUserScaleFactor = userScaleFactor;
|
||||||
|
lastImage = image;
|
||||||
|
|
||||||
|
// paint image
|
||||||
|
paintLastImage( g, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintLastImage( Graphics g, int x, int y ) {
|
||||||
|
if( lastSystemScaleFactor > 1 ) {
|
||||||
|
HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, 100, 100, // width and height are not used
|
||||||
|
(g2, x2, y2, width2, height2, scaleFactor2) -> {
|
||||||
|
g2.drawImage( lastImage, x2, y2, null );
|
||||||
|
} );
|
||||||
|
} else
|
||||||
|
g.drawImage( lastImage, x, y, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scales the given image to the target dimensions.
|
||||||
|
*
|
||||||
|
* This is the same what imgscalr library (https://github.com/rkalla/imgscalr)
|
||||||
|
* would do when invoking Scalr.resize().
|
||||||
|
*/
|
||||||
|
private BufferedImage scaleImage( BufferedImage image, int targetWidth, int targetHeight,
|
||||||
|
Object scalingInterpolation )
|
||||||
|
{
|
||||||
|
BufferedImage bufferedImage = new BufferedImage( targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB );
|
||||||
|
Graphics2D g = bufferedImage.createGraphics();
|
||||||
|
try {
|
||||||
|
g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, scalingInterpolation );
|
||||||
|
g.drawImage( image, 0, 0, targetWidth, targetHeight, null );
|
||||||
|
} finally {
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
return bufferedImage;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage image2bufferedImage( Image image ) {
|
||||||
|
if( image instanceof BufferedImage )
|
||||||
|
return (BufferedImage) image;
|
||||||
|
|
||||||
|
BufferedImage bufferedImage = new BufferedImage( image.getWidth( null ),
|
||||||
|
image.getHeight( null ), BufferedImage.TYPE_INT_ARGB );
|
||||||
|
Graphics2D g = bufferedImage.createGraphics();
|
||||||
|
try {
|
||||||
|
g.drawImage( image, 0, 0, null );
|
||||||
|
} finally {
|
||||||
|
g.dispose();
|
||||||
|
}
|
||||||
|
return bufferedImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import java.awt.image.AbstractMultiResolutionImage;
|
|||||||
import java.awt.image.BaseMultiResolutionImage;
|
import java.awt.image.BaseMultiResolutionImage;
|
||||||
import java.awt.image.MultiResolutionImage;
|
import java.awt.image.MultiResolutionImage;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -51,6 +52,18 @@ public class MultiResolutionImageSupport
|
|||||||
: mapper.apply( image );
|
: mapper.apply( image );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Image getResolutionVariant( Image image, int destImageWidth, int destImageHeight ) {
|
||||||
|
return (image instanceof MultiResolutionImage)
|
||||||
|
? ((MultiResolutionImage)image).getResolutionVariant( destImageWidth, destImageHeight )
|
||||||
|
: image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Image> getResolutionVariants( Image image ) {
|
||||||
|
return (image instanceof MultiResolutionImage)
|
||||||
|
? ((MultiResolutionImage)image).getResolutionVariants()
|
||||||
|
: Collections.singletonList( image );
|
||||||
|
}
|
||||||
|
|
||||||
//---- class MappedMultiResolutionImage -----------------------------------
|
//---- class MappedMultiResolutionImage -----------------------------------
|
||||||
|
|
||||||
private static class MappedMultiResolutionImage
|
private static class MappedMultiResolutionImage
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class FlatChooserTest
|
|||||||
"[]",
|
"[]",
|
||||||
// rows
|
// rows
|
||||||
"[top]" +
|
"[top]" +
|
||||||
"[top]" +
|
"[grow,top]" +
|
||||||
"[]"));
|
"[]"));
|
||||||
|
|
||||||
//---- colorChooserLabel ----
|
//---- colorChooserLabel ----
|
||||||
@@ -73,7 +73,7 @@ public class FlatChooserTest
|
|||||||
//---- fileChooserLabel ----
|
//---- fileChooserLabel ----
|
||||||
fileChooserLabel.setText("JFileChooser:");
|
fileChooserLabel.setText("JFileChooser:");
|
||||||
add(fileChooserLabel, "cell 0 1");
|
add(fileChooserLabel, "cell 0 1");
|
||||||
add(fileChooser1, "cell 1 1");
|
add(fileChooser1, "cell 1 1,growy");
|
||||||
|
|
||||||
//---- label1 ----
|
//---- label1 ----
|
||||||
label1.setText("icons:");
|
label1.setText("icons:");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "7.0.0.0.194" Java: "11.0.2" encoding: "UTF-8"
|
JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.2" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -9,7 +9,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
||||||
"$columnConstraints": "[][]"
|
"$columnConstraints": "[][]"
|
||||||
"$rowConstraints": "[top][top][]"
|
"$rowConstraints": "[top][grow,top][]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "this"
|
name: "this"
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
@@ -32,7 +32,7 @@ new FormModel {
|
|||||||
add( new FormComponent( "javax.swing.JFileChooser" ) {
|
add( new FormComponent( "javax.swing.JFileChooser" ) {
|
||||||
name: "fileChooser1"
|
name: "fileChooser1"
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 1 1"
|
"value": "cell 1 1,growy"
|
||||||
} )
|
} )
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
name: "label1"
|
name: "label1"
|
||||||
|
|||||||
Reference in New Issue
Block a user