From db56486506d600faad3d3d0c43ae99eead5ab36a Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Wed, 16 Jun 2021 12:07:13 +0200 Subject: [PATCH] Styling: support CheckBox and RadioButton (without icons) --- .../formdev/flatlaf/ui/FlatCheckBoxUI.java | 11 ++- .../formdev/flatlaf/ui/FlatRadioButtonUI.java | 96 ++++++++++++++++++- .../formdev/flatlaf/ui/FlatStyleSupport.java | 8 +- .../com/formdev/flatlaf/ui/FlatUIUtils.java | 8 ++ 4 files changed, 116 insertions(+), 7 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCheckBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCheckBoxUI.java index e545fa66..4153d5ff 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCheckBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCheckBoxUI.java @@ -43,7 +43,16 @@ public class FlatCheckBoxUI extends FlatRadioButtonUI { public static ComponentUI createUI( JComponent c ) { - return FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, FlatCheckBoxUI::new ); + return FlatUIUtils.canUseSharedUI( c ) + ? FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, () -> new FlatCheckBoxUI( true ) ) + : new FlatCheckBoxUI( false ); + } + + /** + * @since TODO + */ + protected FlatCheckBoxUI( boolean shared ) { + super( shared ); } @Override 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 56450014..880d904e 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 @@ -23,6 +23,8 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.util.Map; import java.util.Objects; import javax.swing.AbstractButton; import javax.swing.CellRendererPane; @@ -30,7 +32,9 @@ import javax.swing.JComponent; import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicButtonListener; import javax.swing.plaf.basic.BasicRadioButtonUI; +import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.icons.FlatCheckBoxIcon; import com.formdev.flatlaf.util.UIScale; @@ -62,10 +66,28 @@ public class FlatRadioButtonUI private Color defaultBackground; + private final boolean shared; private boolean defaults_initialized = false; + private Map oldStyleValues; public static ComponentUI createUI( JComponent c ) { - return FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, FlatRadioButtonUI::new ); + return FlatUIUtils.canUseSharedUI( c ) + ? FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, () -> new FlatRadioButtonUI( true ) ) + : new FlatRadioButtonUI( false ); + } + + /** + * @since TODO + */ + protected FlatRadioButtonUI( boolean shared ) { + this.shared = shared; + } + + @Override + public void installUI( JComponent c ) { + super.installUI( c ); + + applyStyle( FlatStyleSupport.getStyle( c ) ); } @Override @@ -97,6 +119,56 @@ public class FlatRadioButtonUI defaults_initialized = false; } + @Override + protected BasicButtonListener createButtonListener( AbstractButton b ) { + return new FlatRadioButtonListener( b ); + } + + /** + * @since TODO + */ + protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) { + switch( e.getPropertyName() ) { + case FlatClientProperties.COMPONENT_STYLE: + applyStyle( b, this, e.getNewValue() ); + break; + } + } + + private static void applyStyle( AbstractButton b, FlatRadioButtonUI ui, Object style ) { + // unshare component UI if necessary + if( style != null && ui.shared ) { + b.updateUI(); + ui = (FlatRadioButtonUI) b.getUI(); + } + + ui.applyStyle( style ); + b.revalidate(); + b.repaint(); + } + + /** + * @since TODO + */ + protected void applyStyle( Object style ) { + oldStyleValues = FlatStyleSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); + } + + /** + * @since TODO + */ + protected Object applyStyleProperty( String key, Object value ) { + Object oldValue; + switch( key ) { + case "disabledText": oldValue = disabledText; disabledText = (Color) value; break; + + //TODO style icon + + default: throw new IllegalArgumentException( "unknown style '" + key + "'" ); + } + return oldValue; + } + private static Insets tempInsets = new Insets( 0, 0, 0, 0 ); @Override @@ -182,4 +254,26 @@ public class FlatRadioButtonUI ? UIScale.scale( ((FlatCheckBoxIcon)getDefaultIcon()).focusWidth ) : 0; } + + //---- class FlatRadioButtonListener -------------------------------------- + + /** + * @since TODO + */ + protected class FlatRadioButtonListener + extends BasicButtonListener + { + private final AbstractButton b; + + protected FlatRadioButtonListener( AbstractButton b ) { + super( b ); + this.b = b; + } + + @Override + public void propertyChange( PropertyChangeEvent e ) { + super.propertyChange( e ); + FlatRadioButtonUI.this.propertyChange( b, e ); + } + } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStyleSupport.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStyleSupport.java index 95af2920..efb7853a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStyleSupport.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStyleSupport.java @@ -108,7 +108,7 @@ public class FlatStyleSupport if( style == null || style.trim().isEmpty() ) return null; - Map map = new LinkedHashMap<>(); + Map map = null; // split style into parts and process them for( String part : StringUtils.split( style, ';' ) ) { @@ -131,6 +131,8 @@ public class FlatStyleSupport throw new IllegalArgumentException( "missing value in '" + part + "'" ); // parse value string and convert it into binary value + if( map == null ) + map = new LinkedHashMap<>(); map.put( key, parseValue( key, value ) ); } @@ -144,10 +146,6 @@ public class FlatStyleSupport return FlatLaf.parseDefaultsValue( key, value ); } - public static boolean hasStyle( JComponent c ) { - return getStyle( c ) != null; - } - public static Object getStyle( JComponent c ) { return c.getClientProperty( FlatClientProperties.COMPONENT_STYLE ); } 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 8acbdc1e..4e3cf598 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 @@ -831,6 +831,14 @@ debug*/ .computeIfAbsent( key, k -> newInstanceSupplier.get() ); } + /** + * Returns whether the component UI for the given component can be shared + * with other components. This is only possible if it does not have styles. + */ + public static boolean canUseSharedUI( JComponent c ) { + return FlatStyleSupport.getStyle( c ) == null; + } + //---- class RepaintFocusListener ----------------------------------------- public static class RepaintFocusListener