diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index 2cab462b..37ee9bec 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -40,6 +40,8 @@ import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JRootPane; import javax.swing.JTabbedPane; @@ -52,10 +54,12 @@ import javax.swing.UnsupportedLookAndFeelException; import javax.swing.UIDefaults.ActiveValue; import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.IconUIResource; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.text.StyleContext; import javax.swing.text.html.HTMLEditorKit; +import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.UIScale; @@ -117,6 +121,11 @@ public abstract class FlatLaf return true; } + @Override + public Icon getDisabledIcon( JComponent component, Icon icon ) { + return (icon == null) ? null : new IconUIResource( FlatUIUtils.getDisabledIcon( icon ) ); + } + @Override public void initialize() { if( SystemInfo.IS_MAC ) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java index 4264dfec..2ad5baf1 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java @@ -23,10 +23,15 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; import java.awt.Insets; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; +import java.awt.Toolkit; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseAdapter; @@ -34,7 +39,13 @@ import java.awt.event.MouseEvent; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageProducer; +import java.awt.image.RGBImageFilter; import java.util.function.Consumer; +import javax.swing.Icon; +import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.LookAndFeel; import javax.swing.UIManager; @@ -433,6 +444,59 @@ public class FlatUIUtils return explicitlySet; } + public static Icon getDisabledIcon( Icon icon ) { + Image image = safeGetImage( icon ); + int grayMinValue = FlatUIUtils.getUIInt( "Button.disabledGrayMinValue", 180 ); + int grayMaxValue = FlatUIUtils.getUIInt( "Button.disabledGrayMaxValue", 215 ); + DisabledImageFilter imageFilter = new DisabledImageFilter( grayMinValue, grayMaxValue ); + ImageProducer producer = new FilteredImageSource( image.getSource(), imageFilter ); + return new ImageIcon( Toolkit.getDefaultToolkit().createImage( producer ) ); + } + + private static Image safeGetImage( Icon icon ) { + if( icon instanceof ImageIcon ) { + return ((ImageIcon)icon).getImage(); + } else { + int width = icon.getIconWidth(); + int height = icon.getIconHeight(); + GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice device = environment.getDefaultScreenDevice(); + GraphicsConfiguration configuration = device.getDefaultConfiguration(); + BufferedImage image = configuration.createCompatibleImage( width, height ); + Graphics2D g = image.createGraphics(); + icon.paintIcon( null, g, 0, 0 ); + g.dispose(); + return image; + } + } + + //---- class DisabledImageFilter ------------------------------------------ + + private static class DisabledImageFilter + extends RGBImageFilter + { + private final float min; + private final float factor; + + DisabledImageFilter( int min, int max ) { + this.min = min; + this.factor = (max - min) / 255f; + + canFilterIndexColorModel = true; + } + + @Override + public int filterRGB( int x, int y, int rgb ) { + // https://en.wikipedia.org/wiki/Grayscale + float linearLuminance = + (0.2126f * ((rgb >> 16) & 0xff)) + + (0.7152f * ((rgb >> 8) & 0xff)) + + (0.0722f * (rgb & 0xff)); + int gray = Math.min( (int) ((linearLuminance + .5f) * factor + min), 255 ); + return (rgb & 0xff000000) | (gray << 16) | (gray << 8) | gray; + } + } + //---- class HoverListener ------------------------------------------------ public static class HoverListener