How can I change the “disabled icon” style using SynthLookAndFeel?

Tags: , , ,



I’m currently designing a Swing app with a custom “yellow on black” Look and Feel, and it seems SynthLookAndFeel is the way to go.

All my buttons consist of an ImageIcon (no text), for example: Original

When buttons are disabled, I would like the icons to turn to a faded yellow: Desired

However, the default disabled icons are just greyscale versions of the “enabled” ones, and that breaks the yellow feel: Current

I read in this answer that disabled icons are generated internally by getDisabledIcon(), but I find no place to control it from synth’s XML file.

I also read about SynthLookAndFeel’s SynthPainter class, but it doesn’t seem to address the question of disabled icons.

Is there a way to control that “getDisabledIcon” behaviour using SynthLookAndFeel, or am I asking too much ? In the latter case, what would be the best suited look and feel to use or extend for easy definition of button backgrounds, shapes, etc ?

Any hint is welcome.

Answer

OK, I think I found a clean way.

I was hesitating between finding a way with SynthLookAndFeel or subclassing another L&F… But didn’t think of subclassing SynthLookAndFeel itself 🙂

I’ve now got an implementation of SynthLookAndFeel that does exactly what I want, meaning the “disabled” icon is not a greyscale one, it’s a desaturated, dimmed, color version: enter image description here

Here we go for the full code:

import javax.swing.*;
import javax.swing.plaf.synth.SynthLookAndFeel;
import java.awt.*;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageProducer;
import java.awt.image.RGBImageFilter;

public class MySynthLookAndFeel extends SynthLookAndFeel {
    @Override
    public Icon getDisabledIcon(JComponent component, Icon icon) {
        if (icon instanceof ImageIcon) {
            return new ImageIcon(createDisabledImage(((ImageIcon)icon).getImage()));
        }
        return null;
    }

    private static Image createDisabledImage(Image i) {
        ImageProducer prod = new FilteredImageSource(i.getSource(), new RGBImageFilter() {
            public int filterRGB(int x, int y, int rgb) {
                // extract alpha mask
                int alphamask = rgb & 0xFF000000;

                // convert to HSB
                float[] hsb = Color.RGBtoHSB((rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff, null);
                // desaturate (half saturation)
                hsb[1] *= 0.5;
                // dim (half brightness)
                hsb[2] *= 0.5;
                // convert back to RGB
                int rgbval = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);

                // reapply alpha
                rgbval = rgbval & 0x00FFFFFF | alphamask;
                return rgbval;
            }
        });
        return Toolkit.getDefaultToolkit().createImage(prod);
    }
}

Much simpler than I thought, in the end.



Source: stackoverflow