diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRadioButtonUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRadioButtonUI.java index 5c9bbf88..7c36df31 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRadioButtonUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRadioButtonUI.java @@ -203,16 +203,12 @@ public class FlatRadioButtonUI protected Object applyStyleProperty( AbstractButton b, String key, Object value ) { // style icon if( key.startsWith( "icon." ) ) { - Icon styleIcon = b.getIcon(); - - if (styleIcon == null) - styleIcon = icon; - - if( !(styleIcon instanceof FlatCheckBoxIcon) ) + Icon icon = getRealIcon( b ); + if( !(icon instanceof FlatCheckBoxIcon) ) return new UnknownStyleException( key ); - if( styleIcon == icon && iconShared ) { - icon = FlatStylingSupport.cloneIcon( icon ); + if( icon == this.icon && iconShared ) { + this.icon = icon = FlatStylingSupport.cloneIcon( icon ); iconShared = false; } @@ -230,6 +226,7 @@ public class FlatRadioButtonUI @Override public Map> getStyleableInfos( JComponent c ) { Map> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this ); + Icon icon = getRealIcon( c ); if( icon instanceof FlatCheckBoxIcon ) { for( Map.Entry> e : ((FlatCheckBoxIcon)icon).getStyleableInfos().entrySet() ) infos.put( "icon.".concat( e.getKey() ), e.getValue() ); @@ -242,6 +239,7 @@ public class FlatRadioButtonUI public Object getStyleableValue( JComponent c, String key ) { // style icon if( key.startsWith( "icon." ) ) { + Icon icon = getRealIcon( c ); return (icon instanceof FlatCheckBoxIcon) ? ((FlatCheckBoxIcon)icon).getStyleableValue( key.substring( "icon.".length() ) ) : null; @@ -337,16 +335,18 @@ public class FlatRadioButtonUI } private int getIconFocusWidth( JComponent c ) { - AbstractButton b = (AbstractButton) c; - Icon icon = b.getIcon(); - if( icon == null ) - icon = getDefaultIcon(); - + Icon icon = getRealIcon( c ); return (icon instanceof FlatCheckBoxIcon) ? Math.round( UIScale.scale( ((FlatCheckBoxIcon)icon).getFocusWidth() ) ) : 0; } + private Icon getRealIcon( JComponent c ) { + AbstractButton b = (AbstractButton) c; + Icon icon = b.getIcon(); + return (icon != null) ? icon : getDefaultIcon(); + } + @Override public int getBaseline( JComponent c, int width, int height ) { return FlatButtonUI.getBaselineImpl( c, width, height ); diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java index 4366f280..3f5ce955 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java @@ -30,6 +30,9 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import com.formdev.flatlaf.icons.*; +import com.formdev.flatlaf.ui.TestFlatStyling.CustomCheckBoxIcon; +import com.formdev.flatlaf.ui.TestFlatStyling.CustomIcon; +import com.formdev.flatlaf.ui.TestFlatStyling.CustomRadioButtonIcon; /** * @author Karl Tauber @@ -144,7 +147,12 @@ public class TestFlatStyleableInfo @Test void checkBox() { - JCheckBox c = new JCheckBox(); + checkBox( new JCheckBox() ); + checkBox( new JCheckBox( new CustomIcon() ) ); + checkBox( new JCheckBox( new CustomCheckBoxIcon() ) ); + } + + private void checkBox( JCheckBox c ) { FlatCheckBoxUI ui = (FlatCheckBoxUI) c.getUI(); assertTrue( ui.getDefaultIcon() instanceof FlatCheckBoxIcon ); @@ -153,6 +161,11 @@ public class TestFlatStyleableInfo Map> expected = new LinkedHashMap<>(); radioButton( expected ); + // remove "icon." keys if check box has custom icon + Icon icon = c.getIcon(); + if( icon != null && !(icon instanceof FlatCheckBoxIcon) ) + expected.keySet().removeIf( key -> key.startsWith( "icon." ) ); + assertMapEquals( expected, ui.getStyleableInfos( c ) ); } @@ -492,7 +505,12 @@ public class TestFlatStyleableInfo @Test void radioButton() { - JRadioButton c = new JRadioButton(); + radioButton( new JRadioButton() ); + radioButton( new JRadioButton( new CustomIcon() ) ); + radioButton( new JRadioButton( new CustomRadioButtonIcon() ) ); + } + + private void radioButton( JRadioButton c ) { FlatRadioButtonUI ui = (FlatRadioButtonUI) c.getUI(); assertTrue( ui.getDefaultIcon() instanceof FlatRadioButtonIcon ); @@ -504,6 +522,11 @@ public class TestFlatStyleableInfo "icon.centerDiameter", float.class ); + // remove "icon." keys if radio button has custom icon + Icon icon = c.getIcon(); + if( icon != null && !(icon instanceof FlatRadioButtonIcon) ) + expected.keySet().removeIf( key -> key.startsWith( "icon." ) ); + assertMapEquals( expected, ui.getStyleableInfos( c ) ); } diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java index d4276768..4f0acac9 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java @@ -77,6 +77,9 @@ import com.formdev.flatlaf.icons.FlatRadioButtonMenuItemIcon; import com.formdev.flatlaf.icons.FlatSearchIcon; import com.formdev.flatlaf.icons.FlatSearchWithHistoryIcon; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; +import com.formdev.flatlaf.ui.TestFlatStyling.CustomCheckBoxIcon; +import com.formdev.flatlaf.ui.TestFlatStyling.CustomIcon; +import com.formdev.flatlaf.ui.TestFlatStyling.CustomRadioButtonIcon; /** * @author Karl Tauber @@ -269,11 +272,20 @@ public class TestFlatStyleableValue @Test void checkBox() { - JCheckBox c = new JCheckBox(); + checkBox( new JCheckBox() ); + checkBox( new JCheckBox( new CustomCheckBoxIcon() ) ); + checkBox( new JCheckBox( new CustomIcon() ) ); + } + + private void checkBox( JCheckBox c ) { FlatCheckBoxUI ui = (FlatCheckBoxUI) c.getUI(); // FlatCheckBoxUI extends FlatRadioButtonUI radioButton( ui, c ); + + // necessary to clear FlatRadioButtonUI.oldStyleValues because + // ui.applyStyle(...) operates on shared instance + ui.uninstallUI( c ); } @Test @@ -536,14 +548,24 @@ public class TestFlatStyleableValue @Test void radioButton() { - JRadioButton c = new JRadioButton(); + radioButton( new JRadioButton() ); + radioButton( new JRadioButton( new CustomRadioButtonIcon() ) ); + radioButton( new JRadioButton( new CustomIcon() ) ); + } + + private void radioButton( JRadioButton c ) { FlatRadioButtonUI ui = (FlatRadioButtonUI) c.getUI(); assertTrue( ui.getDefaultIcon() instanceof FlatRadioButtonIcon ); radioButton( ui, c ); - testFloat( c, ui, "icon.centerDiameter", 1.23f ); + if( !(c.getIcon() instanceof CustomIcon) ) + testFloat( c, ui, "icon.centerDiameter", 1.23f ); + + // necessary to clear FlatRadioButtonUI.oldStyleValues because + // ui.applyStyle(...) operates on shared instance + ui.uninstallUI( c ); } private void radioButton( FlatRadioButtonUI ui, AbstractButton b ) { @@ -551,6 +573,11 @@ public class TestFlatStyleableValue //---- icon ---- + if( b.getIcon() instanceof CustomIcon ) { + assertEquals( null, ui.getStyleableValue( b, "icon.focusWidth" ) ); + return; + } + testFloat( b, ui, "icon.focusWidth", 1.23f ); testColor( b, ui, "icon.focusColor", 0x123456 ); testFloat( b, ui, "icon.borderWidth", 1.23f ); diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java index a2057080..4d56f0f1 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java @@ -19,7 +19,9 @@ package com.formdev.flatlaf.ui; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.awt.Color; +import java.awt.Component; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Insets; import java.util.HashMap; import java.util.Map; @@ -294,13 +296,22 @@ public class TestFlatStyling @Test void checkBox() { - JCheckBox c = new JCheckBox(); + checkBox( new JCheckBox() ); + checkBox( new JCheckBox( new CustomIcon() ) ); + checkBox( new JCheckBox( new CustomCheckBoxIcon() ) ); + } + + private void checkBox( JCheckBox c ) { FlatCheckBoxUI ui = (FlatCheckBoxUI) c.getUI(); assertTrue( ui.getDefaultIcon() instanceof FlatCheckBoxIcon ); // FlatCheckBoxUI extends FlatRadioButtonUI radioButton( ui, c ); + + // necessary to clear FlatRadioButtonUI.oldStyleValues because + // ui.applyStyle(...) operates on shared instance + ui.uninstallUI( c ); } @Test @@ -651,14 +662,24 @@ public class TestFlatStyling @Test void radioButton() { - JRadioButton c = new JRadioButton(); + radioButton( new JRadioButton() ); + radioButton( new JRadioButton( new CustomIcon() ) ); + radioButton( new JRadioButton( new CustomRadioButtonIcon() ) ); + } + + private void radioButton( JRadioButton c ) { FlatRadioButtonUI ui = (FlatRadioButtonUI) c.getUI(); assertTrue( ui.getDefaultIcon() instanceof FlatRadioButtonIcon ); radioButton( ui, c ); - ui.applyStyle( c, "icon.centerDiameter: 8" ); + if( !(c.getIcon() instanceof CustomIcon) ) + ui.applyStyle( c, "icon.centerDiameter: 8" ); + + // necessary to clear FlatRadioButtonUI.oldStyleValues because + // ui.applyStyle(...) operates on shared instance + ui.uninstallUI( c ); } private void radioButton( FlatRadioButtonUI ui, AbstractButton b ) { @@ -676,6 +697,9 @@ public class TestFlatStyling //---- icon ---- + if( b.getIcon() instanceof CustomIcon ) + return; + ui.applyStyle( b, "icon.focusWidth: 1.5" ); ui.applyStyle( b, "icon.focusColor: #fff" ); ui.applyStyle( b, "icon.borderWidth: 1.5" ); @@ -1565,4 +1589,34 @@ public class TestFlatStyling UIManager.put( "test.enum", null ); assertEquals( SomeEnum.enumValue1, FlatUIUtils.getUIEnum( "test.enum", SomeEnum.class, SomeEnum.enumValue1 ) ); } + + //---- class CustomIcon --------------------------------------------------- + + static class CustomIcon + implements Icon + { + @Override public void paintIcon( Component c, Graphics g, int x, int y ) {} + @Override public int getIconWidth() { return 1; } + @Override public int getIconHeight() { return 1; } + } + + //---- class CustomCheckBoxIcon ---------------------------------------- + + static class CustomCheckBoxIcon + extends FlatCheckBoxIcon + { + CustomCheckBoxIcon() { + background = Color.green; + } + } + + //---- class CustomRadioButtonIcon ---------------------------------------- + + static class CustomRadioButtonIcon + extends FlatRadioButtonIcon + { + CustomRadioButtonIcon() { + background = Color.green; + } + } }