From b6be0462a5cb0601c360090f35d2c9a11837e99c Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 25 Sep 2021 14:34:21 +0200 Subject: [PATCH] Styling: basic support for "classes" (similar to CSS classes) using client property `FlatLaf.styleClass` --- .../formdev/flatlaf/FlatClientProperties.java | 32 ++ .../com/formdev/flatlaf/ui/FlatButtonUI.java | 19 +- .../flatlaf/ui/FlatCheckBoxMenuItemUI.java | 9 +- .../formdev/flatlaf/ui/FlatCheckBoxUI.java | 6 + .../formdev/flatlaf/ui/FlatComboBoxUI.java | 43 +- .../formdev/flatlaf/ui/FlatEditorPaneUI.java | 15 +- .../flatlaf/ui/FlatFormattedTextFieldUI.java | 6 + .../flatlaf/ui/FlatInternalFrameUI.java | 9 +- .../com/formdev/flatlaf/ui/FlatLabelUI.java | 14 +- .../com/formdev/flatlaf/ui/FlatListUI.java | 10 +- .../com/formdev/flatlaf/ui/FlatMenuBarUI.java | 15 +- .../formdev/flatlaf/ui/FlatMenuItemUI.java | 9 +- .../com/formdev/flatlaf/ui/FlatMenuUI.java | 9 +- .../flatlaf/ui/FlatPasswordFieldUI.java | 6 + .../flatlaf/ui/FlatPopupMenuSeparatorUI.java | 6 + .../formdev/flatlaf/ui/FlatPopupMenuUI.java | 14 +- .../formdev/flatlaf/ui/FlatProgressBarUI.java | 10 +- .../flatlaf/ui/FlatRadioButtonMenuItemUI.java | 9 +- .../formdev/flatlaf/ui/FlatRadioButtonUI.java | 18 +- .../formdev/flatlaf/ui/FlatScrollBarUI.java | 10 +- .../formdev/flatlaf/ui/FlatScrollPaneUI.java | 10 +- .../formdev/flatlaf/ui/FlatSeparatorUI.java | 25 +- .../com/formdev/flatlaf/ui/FlatSliderUI.java | 9 +- .../com/formdev/flatlaf/ui/FlatSpinnerUI.java | 10 +- .../formdev/flatlaf/ui/FlatSplitPaneUI.java | 14 +- .../flatlaf/ui/FlatStylingSupport.java | 163 ++++++- .../formdev/flatlaf/ui/FlatTabbedPaneUI.java | 10 +- .../formdev/flatlaf/ui/FlatTableHeaderUI.java | 14 +- .../com/formdev/flatlaf/ui/FlatTableUI.java | 10 +- .../formdev/flatlaf/ui/FlatTextAreaUI.java | 9 +- .../formdev/flatlaf/ui/FlatTextFieldUI.java | 15 +- .../formdev/flatlaf/ui/FlatTextPaneUI.java | 9 +- .../flatlaf/ui/FlatToggleButtonUI.java | 5 + .../flatlaf/ui/FlatToolBarSeparatorUI.java | 20 +- .../com/formdev/flatlaf/ui/FlatToolBarUI.java | 9 +- .../com/formdev/flatlaf/ui/FlatTreeUI.java | 10 +- .../com/formdev/flatlaf/ui/FlatUIUtils.java | 6 +- .../flatlaf/ui/MigLayoutVisualPadding.java | 4 +- .../flatlaf/ui/TestFlatStyleClasses.java | 448 ++++++++++++++++++ 39 files changed, 951 insertions(+), 118 deletions(-) create mode 100644 flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleClasses.java diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java index c601eca4..f4b4e03d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -145,6 +145,38 @@ public interface FlatClientProperties */ String STYLE = "FlatLaf.style"; + /** + * Specifies the style class(es) of a component as String + * or as {@link java.util.List}<String>. + *

+ * The style rules must be defined in UI defaults either as strings (in CSS syntax) + * or as {@link java.util.Map}<String, Object> (with binary values). + * The key must be in syntax: {@code [style]type.styleClass}, where the type is optional. + * E.g. in FlatLaf properties file: + *

{@code
+	 * [style]Button.primary = borderColor: #08f; background: #08f; foreground: #fff
+	 * [style].secondary = borderColor: #0f8; background: #0f8
+	 * }
+ * or in Java code: + *
{@code
+	 * UIManager.put( "[style]Button.primary", "borderColor: #08f; background: #08f; foreground: #fff" );
+	 * UIManager.put( "[style].secondary", "borderColor: #0f8; background: #0f8" );
+	 * }
+ * The rule "Button.primary" can be applied to buttons only. + * The rule ".secondary" can be applied to any component. + *

+ * To have similar behaviour as in CSS, first the rule without type is applied, + * then the rule with type. + * E.g. setting style class to "foo" on a {@code JButton} uses rules + * from UI default keys "[style].foo" and "[style]Button.foo". + *

+ * Components {@link javax.swing.JComponent}
+ * Value type {@link java.lang.String}, {@code String[]} or {@link java.util.List}<String>
+ * + * @since 2 + */ + String STYLE_CLASS = "FlatLaf.styleClass"; + /** * Specifies minimum width of a component. *

diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java index 0465e7d0..a29c4626 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java @@ -152,6 +152,7 @@ public class FlatButtonUI : new FlatButtonUI( false ); } + /** @since 2 */ protected FlatButtonUI( boolean shared ) { this.shared = shared; } @@ -160,7 +161,7 @@ public class FlatButtonUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( (AbstractButton) c, FlatStylingSupport.getStyle( c ) ); + installStyle( (AbstractButton) c ); } @Override @@ -254,19 +255,29 @@ public class FlatButtonUI break; case STYLE: - Object style = e.getNewValue(); - if( style != null && shared ) { + case STYLE_CLASS: + if( shared && FlatStylingSupport.hasStyleProperty( b ) ) { // unshare component UI if necessary // updateUI() invokes applyStyle() from installUI() b.updateUI(); } else - applyStyle( b, style ); + installStyle( b ); b.revalidate(); b.repaint(); break; } } + /** @since 2 */ + protected void installStyle( AbstractButton b ) { + applyStyle( b, FlatStylingSupport.getResolvedStyle( b, getStyleType() ) ); + } + + /** @since 2 */ + String getStyleType() { + return "Button"; + } + /** @since 2 */ protected void applyStyle( AbstractButton b, Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCheckBoxMenuItemUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCheckBoxMenuItemUI.java index 5db876ba..b78ca31d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCheckBoxMenuItemUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCheckBoxMenuItemUI.java @@ -72,7 +72,7 @@ public class FlatCheckBoxMenuItemUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( menuItem ) ); + installStyle(); } @Override @@ -98,7 +98,12 @@ public class FlatCheckBoxMenuItemUI @Override protected PropertyChangeListener createPropertyChangeListener( JComponent c ) { - return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) ); + return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) ); + } + + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "CheckBoxMenuItem" ) ); } /** @since 2 */ 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 0c407fd6..354b30b1 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 @@ -57,4 +57,10 @@ public class FlatCheckBoxUI public String getPropertyPrefix() { return "CheckBox."; } + + /** @since 2 */ + @Override + String getStyleType() { + return "CheckBox"; + } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index 1d438c7e..25f086bf 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java @@ -16,6 +16,7 @@ package com.formdev.flatlaf.ui; +import static com.formdev.flatlaf.FlatClientProperties.*; import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.unscale; import java.awt.Color; @@ -69,7 +70,6 @@ import javax.swing.plaf.basic.BasicComboBoxUI; import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.plaf.basic.ComboPopup; import javax.swing.text.JTextComponent; -import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.util.SystemInfo; @@ -155,7 +155,7 @@ public class FlatComboBoxUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( comboBox ) ); + installStyle(); } @Override @@ -341,16 +341,28 @@ public class FlatComboBoxUI } else if( editor != null && source == comboBox && propertyName == "componentOrientation" ) { ComponentOrientation o = (ComponentOrientation) e.getNewValue(); editor.applyComponentOrientation( o ); - } else if( editor != null && FlatClientProperties.PLACEHOLDER_TEXT.equals( propertyName ) ) - editor.repaint(); - else if( FlatClientProperties.COMPONENT_ROUND_RECT.equals( propertyName ) ) - comboBox.repaint(); - else if( FlatClientProperties.MINIMUM_WIDTH.equals( propertyName ) ) - comboBox.revalidate(); - else if( FlatClientProperties.STYLE.equals( propertyName ) ) { - applyStyle( e.getNewValue() ); - comboBox.revalidate(); - comboBox.repaint(); + } else { + switch( propertyName ) { + case PLACEHOLDER_TEXT: + if( editor != null ) + editor.repaint(); + break; + + case COMPONENT_ROUND_RECT: + comboBox.repaint(); + break; + + case MINIMUM_WIDTH: + comboBox.revalidate(); + break; + + case STYLE: + case STYLE_CLASS: + installStyle(); + comboBox.revalidate(); + comboBox.repaint(); + break; + } } }; } @@ -419,7 +431,7 @@ public class FlatComboBoxUI unscale( Math.max( scale( padding.right ) - insets.right, 0 ) ) ); } - textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, pad ); + textField.putClientProperty( TEXT_FIELD_PADDING, pad ); } private void updateEditorColors() { @@ -438,6 +450,11 @@ public class FlatComboBoxUI return new FlatComboBoxButton(); } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( comboBox, "ComboBox" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { Insets oldPadding = padding; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatEditorPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatEditorPaneUI.java index 3fe21d52..6c9cb714 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatEditorPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatEditorPaneUI.java @@ -25,7 +25,6 @@ import java.awt.Insets; import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; import java.util.Map; -import java.util.function.Consumer; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.UIManager; @@ -91,7 +90,7 @@ public class FlatEditorPaneUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -155,23 +154,29 @@ public class FlatEditorPaneUI updateBackground(); super.propertyChange( e ); - propertyChange( getComponent(), e, this::applyStyle ); + propertyChange( getComponent(), e, this::installStyle ); } - static void propertyChange( JTextComponent c, PropertyChangeEvent e, Consumer applyStyle ) { + static void propertyChange( JTextComponent c, PropertyChangeEvent e, Runnable installStyle ) { switch( e.getPropertyName() ) { case FlatClientProperties.MINIMUM_WIDTH: c.revalidate(); break; case FlatClientProperties.STYLE: - applyStyle.accept( e.getNewValue() ); + case FlatClientProperties.STYLE_CLASS: + installStyle.run(); c.revalidate(); c.repaint(); break; } } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "EditorPane" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldDisabledBackground = disabledBackground; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java index 6e34a643..5f390de8 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java @@ -60,4 +60,10 @@ public class FlatFormattedTextFieldUI protected String getPropertyPrefix() { return "FormattedTextField"; } + + /** @since 2 */ + @Override + String getStyleType() { + return "FormattedTextField"; + } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java index b11acd16..32460cda 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java @@ -116,7 +116,7 @@ public class FlatInternalFrameUI windowResizer = createWindowResizer(); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -148,10 +148,15 @@ public class FlatInternalFrameUI @Override protected PropertyChangeListener createPropertyChangeListener() { - return FlatStylingSupport.createPropertyChangeListener( frame, this::applyStyle, + return FlatStylingSupport.createPropertyChangeListener( frame, this::installStyle, super.createPropertyChangeListener() ); } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( frame, "InternalFrame" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatLabelUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatLabelUI.java index e90e4df5..2c16494a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatLabelUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatLabelUI.java @@ -81,7 +81,7 @@ public class FlatLabelUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( (JLabel) c, FlatStylingSupport.getStyle( c ) ); + installStyle( (JLabel) c ); } @Override @@ -117,21 +117,25 @@ public class FlatLabelUI if( name == "text" || name == "font" || name == "foreground" ) { JLabel label = (JLabel) e.getSource(); updateHTMLRenderer( label, label.getText(), true ); - } else if( name.equals( FlatClientProperties.STYLE ) ) { + } else if( name.equals( FlatClientProperties.STYLE ) || name.equals( FlatClientProperties.STYLE_CLASS ) ) { JLabel label = (JLabel) e.getSource(); - Object style = e.getNewValue(); - if( style != null && shared ) { + if( shared && FlatStylingSupport.hasStyleProperty( label ) ) { // unshare component UI if necessary // updateUI() invokes applyStyle() from installUI() label.updateUI(); } else - applyStyle( label, style ); + installStyle( label ); label.revalidate(); label.repaint(); } else super.propertyChange( e ); } + /** @since 2 */ + protected void installStyle( JLabel c ) { + applyStyle( c, FlatStylingSupport.getResolvedStyle( c, "Label" ) ); + } + /** @since 2 */ protected void applyStyle( JLabel c, Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatListUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatListUI.java index 9e1cb035..956c6b76 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatListUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatListUI.java @@ -91,7 +91,7 @@ public class FlatListUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -151,7 +151,8 @@ public class FlatListUI break; case FlatClientProperties.STYLE: - applyStyle( e.getNewValue() ); + case FlatClientProperties.STYLE_CLASS: + installStyle(); list.revalidate(); list.repaint(); break; @@ -159,6 +160,11 @@ public class FlatListUI }; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( list, "List" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { Color oldSelectionBackground = selectionBackground; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java index 2e09ecf4..a0e5280a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java @@ -39,7 +39,6 @@ import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicMenuBarUI; -import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; @@ -91,7 +90,7 @@ public class FlatMenuBarUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -113,16 +112,15 @@ public class FlatMenuBarUI protected void installListeners() { super.installListeners(); - propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( - menuBar, this::applyStyle, null ); - menuBar.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( menuBar, this::installStyle, null ); + menuBar.addPropertyChangeListener( propertyChangeListener ); } @Override protected void uninstallListeners() { super.uninstallListeners(); - menuBar.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + menuBar.removePropertyChangeListener( propertyChangeListener ); propertyChangeListener = null; } @@ -138,6 +136,11 @@ public class FlatMenuBarUI map.put( "takeFocus", new TakeFocus() ); } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( menuBar, "MenuBar" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemUI.java index 541d0c5a..0b7b9516 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemUI.java @@ -73,7 +73,7 @@ public class FlatMenuItemUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( menuItem ) ); + installStyle(); } @Override @@ -99,7 +99,12 @@ public class FlatMenuItemUI @Override protected PropertyChangeListener createPropertyChangeListener( JComponent c ) { - return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) ); + return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) ); + } + + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "MenuItem" ) ); } /** @since 2 */ diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuUI.java index 2805f529..009c505a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuUI.java @@ -92,7 +92,7 @@ public class FlatMenuUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( menuItem ) ); + installStyle(); } @Override @@ -145,7 +145,12 @@ public class FlatMenuUI @Override protected PropertyChangeListener createPropertyChangeListener( JComponent c ) { - return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) ); + return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) ); + } + + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "Menu" ) ); } /** @since 2 */ diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java index 56438e23..69c93889 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java @@ -162,6 +162,12 @@ public class FlatPasswordFieldUI } } + /** @since 2 */ + @Override + String getStyleType() { + return "PasswordField"; + } + /** @since 2 */ @Override protected Object applyStyleProperty( String key, Object value ) { diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuSeparatorUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuSeparatorUI.java index 136983f9..c0837476 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuSeparatorUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuSeparatorUI.java @@ -53,4 +53,10 @@ public class FlatPopupMenuSeparatorUI protected String getPropertyPrefix() { return "PopupMenuSeparator"; } + + /** @since 2 */ + @Override + String getStyleType() { + return "PopupMenuSeparator"; + } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuUI.java index 78d348ed..1b7c1b12 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuUI.java @@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicPopupMenuUI; -import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; /** @@ -53,7 +52,7 @@ public class FlatPopupMenuUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -68,18 +67,23 @@ public class FlatPopupMenuUI protected void installListeners() { super.installListeners(); - propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( popupMenu, this::applyStyle, null ); - popupMenu.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( popupMenu, this::installStyle, null ); + popupMenu.addPropertyChangeListener( propertyChangeListener ); } @Override protected void uninstallListeners() { super.uninstallListeners(); - popupMenu.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + popupMenu.removePropertyChangeListener( propertyChangeListener ); propertyChangeListener = null; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( popupMenu, "PopupMenu" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatProgressBarUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatProgressBarUI.java index bfae831a..9af3a538 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatProgressBarUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatProgressBarUI.java @@ -78,7 +78,7 @@ public class FlatProgressBarUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( progressBar ) ); + installStyle(); } @Override @@ -112,7 +112,8 @@ public class FlatProgressBarUI break; case STYLE: - applyStyle( e.getNewValue() ); + case STYLE_CLASS: + installStyle(); progressBar.revalidate(); progressBar.repaint(); break; @@ -129,6 +130,11 @@ public class FlatProgressBarUI propertyChangeListener = null; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( progressBar, "ProgressBar" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRadioButtonMenuItemUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRadioButtonMenuItemUI.java index 0309ae13..5cab968e 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRadioButtonMenuItemUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRadioButtonMenuItemUI.java @@ -72,7 +72,7 @@ public class FlatRadioButtonMenuItemUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( menuItem ) ); + installStyle(); } @Override @@ -98,7 +98,12 @@ public class FlatRadioButtonMenuItemUI @Override protected PropertyChangeListener createPropertyChangeListener( JComponent c ) { - return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) ); + return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) ); + } + + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "RadioButtonMenuItem" ) ); } /** @since 2 */ 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 fbe719b2..75be18d9 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 @@ -90,7 +90,7 @@ public class FlatRadioButtonUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( (AbstractButton) c, FlatStylingSupport.getStyle( c ) ); + installStyle( (AbstractButton) c ); } @Override @@ -134,19 +134,29 @@ public class FlatRadioButtonUI protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) { switch( e.getPropertyName() ) { case FlatClientProperties.STYLE: - Object style = e.getNewValue(); - if( style != null && shared ) { + case FlatClientProperties.STYLE_CLASS: + if( shared && FlatStylingSupport.hasStyleProperty( b ) ) { // unshare component UI if necessary // updateUI() invokes applyStyle() from installUI() b.updateUI(); } else - applyStyle( b, style ); + installStyle( b ); b.revalidate(); b.repaint(); break; } } + /** @since 2 */ + protected void installStyle( AbstractButton b ) { + applyStyle( b, FlatStylingSupport.getResolvedStyle( b, getStyleType() ) ); + } + + /** @since 2 */ + String getStyleType() { + return "RadioButton"; + } + /** @since 2 */ protected void applyStyle( AbstractButton b, Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollBarUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollBarUI.java index 7e6f23d0..f2f32e40 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollBarUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollBarUI.java @@ -115,7 +115,7 @@ public class FlatScrollBarUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -199,7 +199,8 @@ public class FlatScrollBarUI break; case FlatClientProperties.STYLE: - applyStyle( e.getNewValue() ); + case FlatClientProperties.STYLE_CLASS: + installStyle(); scrollbar.revalidate(); scrollbar.repaint(); break; @@ -220,6 +221,11 @@ public class FlatScrollBarUI }; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( scrollbar, "ScrollBar" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java index c7f65b65..8adb6c6a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java @@ -87,7 +87,7 @@ public class FlatScrollPaneUI int focusWidth = UIManager.getInt( "Component.focusWidth" ); LookAndFeel.installProperty( c, "opaque", focusWidth == 0 ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); MigLayoutVisualPadding.install( scrollpane ); } @@ -287,7 +287,8 @@ public class FlatScrollPaneUI break; case FlatClientProperties.STYLE: - applyStyle( e.getNewValue() ); + case FlatClientProperties.STYLE_CLASS: + installStyle(); scrollpane.revalidate(); scrollpane.repaint(); break; @@ -301,6 +302,11 @@ public class FlatScrollPaneUI return handler; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( scrollpane, "ScrollPane" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSeparatorUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSeparatorUI.java index ebcdfc14..b002b0e5 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSeparatorUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSeparatorUI.java @@ -28,7 +28,6 @@ import javax.swing.JSeparator; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSeparatorUI; -import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; @@ -80,7 +79,7 @@ public class FlatSeparatorUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( (JSeparator) c, FlatStylingSupport.getStyle( c ) ); + installStyle( (JSeparator) c ); } @Override @@ -110,29 +109,39 @@ public class FlatSeparatorUI super.installListeners( s ); propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( - s, style -> applyStyle( s, this, style ), null ); - s.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + s, () -> stylePropertyChange( s ), null ); + s.addPropertyChangeListener( propertyChangeListener ); } @Override protected void uninstallListeners( JSeparator s ) { super.uninstallListeners( s ); - s.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + s.removePropertyChangeListener( propertyChangeListener ); propertyChangeListener = null; } - private static void applyStyle( JSeparator s, FlatSeparatorUI ui, Object style ) { - if( style != null && ui.shared ) { + private void stylePropertyChange( JSeparator s ) { + if( shared && FlatStylingSupport.hasStyleProperty( s ) ) { // unshare component UI if necessary // updateUI() invokes applyStyle() from installUI() s.updateUI(); } else - ui.applyStyle( s, style ); + installStyle( s ); s.revalidate(); s.repaint(); } + /** @since 2 */ + protected void installStyle( JSeparator s ) { + applyStyle( s, FlatStylingSupport.getResolvedStyle( s, getStyleType() ) ); + } + + /** @since 2 */ + String getStyleType() { + return "Separator"; + } + /** @since 2 */ protected void applyStyle( JSeparator s, Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java index 79c09caa..bb65102b 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java @@ -121,7 +121,7 @@ public class FlatSliderUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( slider ) ); + installStyle(); } @Override @@ -188,10 +188,15 @@ public class FlatSliderUI @Override protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) { - return FlatStylingSupport.createPropertyChangeListener( slider, this::applyStyle, + return FlatStylingSupport.createPropertyChangeListener( slider, this::installStyle, super.createPropertyChangeListener( slider ) ); } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( slider, "Slider" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java index a0f87b5d..8819b32a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java @@ -114,7 +114,7 @@ public class FlatSpinnerUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( spinner ) ); + installStyle(); } @Override @@ -190,6 +190,11 @@ public class FlatSpinnerUI return handler; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( spinner, "Spinner" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); @@ -530,7 +535,8 @@ public class FlatSpinnerUI break; case FlatClientProperties.STYLE: - applyStyle( e.getNewValue() ); + case FlatClientProperties.STYLE_CLASS: + installStyle(); spinner.revalidate(); spinner.repaint(); break; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSplitPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSplitPaneUI.java index 667cca3b..6d537a72 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSplitPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSplitPaneUI.java @@ -34,7 +34,6 @@ import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneUI; -import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException; @@ -90,7 +89,7 @@ public class FlatSplitPaneUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( splitPane ) ); + installStyle(); } @Override @@ -121,15 +120,15 @@ public class FlatSplitPaneUI protected void installListeners() { super.installListeners(); - propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::applyStyle, null ); - splitPane.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle, null ); + splitPane.addPropertyChangeListener( propertyChangeListener ); } @Override protected void uninstallListeners() { super.uninstallListeners(); - splitPane.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + splitPane.removePropertyChangeListener( propertyChangeListener ); propertyChangeListener = null; } @@ -138,6 +137,11 @@ public class FlatSplitPaneUI return new FlatSplitPaneDivider( this ); } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( splitPane, "SplitPane" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStylingSupport.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStylingSupport.java index 6afeb8d8..49ab18e3 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStylingSupport.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStylingSupport.java @@ -26,10 +26,10 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiFunction; -import java.util.function.Consumer; import java.util.function.Predicate; import javax.swing.Icon; import javax.swing.JComponent; @@ -73,6 +73,150 @@ public class FlatStylingSupport Map> getStyleableInfos(); } + + /** + * Returns the style specified in client property {@link FlatClientProperties#STYLE}. + */ + public static Object getStyle( JComponent c ) { + return c.getClientProperty( FlatClientProperties.STYLE ); + } + + /** + * Returns the style class(es) specified in client property {@link FlatClientProperties#STYLE_CLASS}. + */ + public static Object getStyleClass( JComponent c ) { + return c.getClientProperty( FlatClientProperties.STYLE_CLASS ); + } + + static boolean hasStyleProperty( JComponent c ) { + return getStyle( c ) != null || getStyleClass( c ) != null; + } + + public static Object getResolvedStyle( JComponent c, String type ) { + Object style = getStyle( c ); + Object styleClass = getStyleClass( c ); + Object styleForClasses = getStyleForClasses( styleClass, type ); + return joinStyles( styleForClasses, style ); + } + + /** + * Returns the styles for the given style class(es) and the given type. + *

+ * The style rules must be defined in UI defaults either as strings (in CSS syntax) + * or as {@link java.util.Map}<String, Object> (with binary values). + * The key must be in syntax: {@code [style]type.styleClass}, where the type is optional. + * E.g. in FlatLaf properties file: + *

{@code
+	 * [style]Button.primary = borderColor: #08f; background: #08f; foreground: #fff
+	 * [style].secondary = borderColor: #0f8; background: #0f8
+	 * }
+ * or in Java code: + *
{@code
+	 * UIManager.put( "[style]Button.primary", "borderColor: #08f; background: #08f; foreground: #fff" );
+	 * UIManager.put( "[style].secondary", "borderColor: #0f8; background: #0f8" );
+	 * }
+ * The rule "Button.primary" can be applied to buttons only. + * The rule ".secondary" can be applied to any component. + *

+ * To have similar behaviour as in CSS, this method first gets the rule without type, + * then the rule with type and concatenates both rules. + * E.g. invoking this method with parameters styleClass="foo" and type="Button" does following: + *

{@code
+	 * return joinStyles(
+	 *     UIManager.get( "[style].foo" ),
+	 *     UIManager.get( "[style]Button.foo" ) );
+	 * }
+ * + * @param styleClass the style class(es) either as string (single class) + * or as {@code String[]} or {@link java.util.List}<String> (multiple classes) + * @param type the type of the component + * @return the styles + */ + public static Object getStyleForClasses( Object styleClass, String type ) { + if( styleClass == null ) + return null; + + if( styleClass instanceof String ) + return getStyleForClass( (String) styleClass, type ); + else if( styleClass instanceof String[] ) { + Object style = null; + for( String cls : (String[]) styleClass ) + style = joinStyles( style, getStyleForClass( cls, type ) ); + return style; + } else if( styleClass instanceof List ) { + Object style = null; + for( Object cls : (List) styleClass ) + style = joinStyles( style, getStyleForClass( (String) cls, type ) ); + return style; + } else + return null; + } + + private static Object getStyleForClass( String styleClass, String type ) { + return joinStyles( + UIManager.get( "[style]." + styleClass ), + UIManager.get( "[style]" + type + '.' + styleClass ) ); + } + + /** + * Joins two styles. They can be either strings (in CSS syntax) + * or {@link java.util.Map}<String, Object> (with binary values). + *

+ * If both styles are strings, then a joined string is returned. + * If both styles are maps, then a joined map is returned. + * If one style is a map and the other style a string, then the string + * is parsed (using {@link #parse(String)}) to a map and a joined map is returned. + * + * @param style1 first style as string or map, or {@code null} + * @param style2 second style as string or map, or {@code null} + * @return new joined style + */ + @SuppressWarnings( "unchecked" ) + public static Object joinStyles( Object style1, Object style2 ) { + if( style1 == null ) + return style2; + if( style2 == null ) + return style1; + + // join two strings + if( style1 instanceof String && style2 instanceof String ) + return style1 + "; " + style2; + + // convert first style to map + Map map1 = (style1 instanceof String) + ? parse( (String) style1 ) + : (Map) style1; + if( map1 == null ) + return style2; + + // convert second style to map + Map map2 = (style2 instanceof String) + ? parse( (String) style2 ) + : (Map) style2; + if( map2 == null ) + return style1; + + // join two maps + Map map = new HashMap<>( map1 ); + map.putAll( map2 ); + return map; + } + + /** + * Concatenates two styles in CSS syntax. + * + * @param style1 first style, or {@code null} + * @param style2 second style, or {@code null} + * @return concatenation of the two styles separated by a semicolon + */ + public static String concatStyles( String style1, String style2 ) { + if( style1 == null ) + return style2; + if( style2 == null ) + return style1; + return style1 + "; " + style2; + } + /** * Parses styles in CSS syntax ("key1: value1; key2: value2; ..."), * converts the value strings into binary and invokes the given function @@ -408,21 +552,20 @@ public class FlatStylingSupport } } - public static Object getStyle( JComponent c ) { - return c.getClientProperty( FlatClientProperties.STYLE ); - } - static PropertyChangeListener createPropertyChangeListener( JComponent c, - Consumer applyStyle, PropertyChangeListener superListener ) + Runnable installStyle, PropertyChangeListener superListener ) { return e -> { if( superListener != null ) superListener.propertyChange( e ); - if( FlatClientProperties.STYLE.equals( e.getPropertyName() ) ) { - applyStyle.accept( e.getNewValue() ); - c.revalidate(); - c.repaint(); + switch( e.getPropertyName() ) { + case FlatClientProperties.STYLE: + case FlatClientProperties.STYLE_CLASS: + installStyle.run(); + c.revalidate(); + c.repaint(); + break; } }; } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java index f310f997..67d900be 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java @@ -269,7 +269,7 @@ public class FlatTabbedPaneUI super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -572,6 +572,11 @@ public class FlatTabbedPaneUI return new FlatScrollableTabButton( direction ); } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( tabPane, "TabbedPane" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); @@ -2439,7 +2444,8 @@ public class FlatTabbedPaneUI break; case STYLE: - applyStyle( e.getNewValue() ); + case STYLE_CLASS: + installStyle(); tabPane.revalidate(); tabPane.repaint(); break; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java index f8540966..0c0904b5 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java @@ -41,7 +41,6 @@ import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicTableHeaderUI; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumnModel; -import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.util.UIScale; @@ -104,7 +103,7 @@ public class FlatTableHeaderUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -129,18 +128,23 @@ public class FlatTableHeaderUI protected void installListeners() { super.installListeners(); - propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( header, this::applyStyle, null ); - header.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( header, this::installStyle, null ); + header.addPropertyChangeListener( propertyChangeListener ); } @Override protected void uninstallListeners() { super.uninstallListeners(); - header.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + header.removePropertyChangeListener( propertyChangeListener ); propertyChangeListener = null; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( header, "TableHeader" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java index 86bc82a0..b3df21f3 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java @@ -126,7 +126,7 @@ public class FlatTableUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -197,7 +197,8 @@ public class FlatTableUI break; case FlatClientProperties.STYLE: - applyStyle( e.getNewValue() ); + case FlatClientProperties.STYLE_CLASS: + installStyle(); table.revalidate(); table.repaint(); break; @@ -235,6 +236,11 @@ public class FlatTableUI }; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( table, "Table" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { Color oldSelectionBackground = selectionBackground; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java index dff2f9d1..244757e3 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java @@ -86,7 +86,7 @@ public class FlatTextAreaUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -143,7 +143,12 @@ public class FlatTextAreaUI updateBackground(); super.propertyChange( e ); - FlatEditorPaneUI.propertyChange( getComponent(), e, this::applyStyle ); + FlatEditorPaneUI.propertyChange( getComponent(), e, this::installStyle ); + } + + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "TextArea" ) ); } /** @since 2 */ diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java index 51297da0..2e676135 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java @@ -114,7 +114,7 @@ public class FlatTextFieldUI leadingIcon = clientProperty( c, TEXT_FIELD_LEADING_ICON, null, Icon.class ); trailingIcon = clientProperty( c, TEXT_FIELD_TRAILING_ICON, null, Icon.class ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -209,7 +209,8 @@ public class FlatTextFieldUI break; case STYLE: - applyStyle( e.getNewValue() ); + case STYLE_CLASS: + installStyle(); c.revalidate(); c.repaint(); break; @@ -226,6 +227,16 @@ public class FlatTextFieldUI } } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), getStyleType() ) ); + } + + /** @since 2 */ + String getStyleType() { + return "TextField"; + } + /** @since 2 */ protected void applyStyle( Object style ) { oldDisabledBackground = disabledBackground; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextPaneUI.java index de5b870c..5aa3b6a1 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextPaneUI.java @@ -87,7 +87,7 @@ public class FlatTextPaneUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -151,7 +151,12 @@ public class FlatTextPaneUI updateBackground(); super.propertyChange( e ); - FlatEditorPaneUI.propertyChange( getComponent(), e, this::applyStyle ); + FlatEditorPaneUI.propertyChange( getComponent(), e, this::installStyle ); + } + + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "TextPane" ) ); } /** @since 2 */ diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToggleButtonUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToggleButtonUI.java index a029e740..89e1492f 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToggleButtonUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToggleButtonUI.java @@ -96,6 +96,11 @@ public class FlatToggleButtonUI super( shared ); } + @Override + String getStyleType() { + return "ToggleButton"; + } + @Override protected String getPropertyPrefix() { return "ToggleButton."; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarSeparatorUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarSeparatorUI.java index 0978cc99..865fe3a2 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarSeparatorUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarSeparatorUI.java @@ -31,7 +31,6 @@ import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicToolBarSeparatorUI; -import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; @@ -74,7 +73,7 @@ public class FlatToolBarSeparatorUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle( (JSeparator) c ); } @Override @@ -106,29 +105,34 @@ public class FlatToolBarSeparatorUI super.installListeners( s ); propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( - s, style -> applyStyle( s, this, style ), null ); - s.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + s, () -> stylePropertyChange( s ), null ); + s.addPropertyChangeListener( propertyChangeListener ); } @Override protected void uninstallListeners( JSeparator s ) { super.uninstallListeners( s ); - s.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + s.removePropertyChangeListener( propertyChangeListener ); propertyChangeListener = null; } - private static void applyStyle( JSeparator s, FlatToolBarSeparatorUI ui, Object style ) { - if( style != null && ui.shared ) { + private void stylePropertyChange( JSeparator s ) { + if( shared && FlatStylingSupport.hasStyleProperty( s ) ) { // unshare component UI if necessary // updateUI() invokes applyStyle() from installUI() s.updateUI(); } else - ui.applyStyle( style ); + installStyle( s ); s.revalidate(); s.repaint(); } + /** @since 2 */ + protected void installStyle( JSeparator s ) { + applyStyle( FlatStylingSupport.getResolvedStyle( s, "ToolBarSeparator" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java index f863e6c4..291bd0f4 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java @@ -83,7 +83,7 @@ public class FlatToolBarUI if( !focusableButtons ) setButtonsFocusable( false ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -133,7 +133,12 @@ public class FlatToolBarUI @Override protected PropertyChangeListener createPropertyListener() { - return FlatStylingSupport.createPropertyChangeListener( toolBar, this::applyStyle, super.createPropertyListener() ); + return FlatStylingSupport.createPropertyChangeListener( toolBar, this::installStyle, super.createPropertyListener() ); + } + + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( toolBar, "ToolBar" ) ); } /** @since 2 */ diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java index 68d9b842..531b732e 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTreeUI.java @@ -156,7 +156,7 @@ public class FlatTreeUI public void installUI( JComponent c ) { super.installUI( c ); - applyStyle( FlatStylingSupport.getStyle( c ) ); + installStyle(); } @Override @@ -271,7 +271,8 @@ public class FlatTreeUI break; case STYLE: - applyStyle( e.getNewValue() ); + case STYLE_CLASS: + installStyle(); tree.revalidate(); tree.repaint(); break; @@ -309,6 +310,11 @@ public class FlatTreeUI return bounds; } + /** @since 2 */ + protected void installStyle() { + applyStyle( FlatStylingSupport.getResolvedStyle( tree, "Tree" ) ); + } + /** @since 2 */ protected void applyStyle( Object style ) { oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); 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 795fe2c7..fc3777a7 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 @@ -370,14 +370,16 @@ public class FlatUIUtils *
  • an (optional) component border *
  • the (optional) component background * + *

    + * * Each part is painted only if the corresponding part color is not {@code null}. * The parts are painted in this order: - *

    *

      *
    1. background *
    2. focus border *
    3. border *
    + *

    * * Background: * The bounds of the filled round rectangle are @@ -939,7 +941,7 @@ debug*/ * with other components. This is only possible if it does not have styles. */ public static boolean canUseSharedUI( JComponent c ) { - return FlatStylingSupport.getStyle( c ) == null; + return !FlatStylingSupport.hasStyleProperty( c ); } //---- class RepaintFocusListener ----------------------------------------- diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/MigLayoutVisualPadding.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/MigLayoutVisualPadding.java index 7df37989..89389ab9 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/MigLayoutVisualPadding.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/MigLayoutVisualPadding.java @@ -81,7 +81,7 @@ public class MigLayoutVisualPadding return new Insets( focusWidth, focusWidth, focusWidth, focusWidth ); } else return null; - }, "border", FlatClientProperties.STYLE ); + }, "border", FlatClientProperties.STYLE, FlatClientProperties.STYLE_CLASS ); } /** @@ -100,7 +100,7 @@ public class MigLayoutVisualPadding c.addPropertyChangeListener( (FlatMigListener) e -> { String propertyName = e.getPropertyName(); for( String name : propertyNames ) { - if( name == propertyName ) { + if( name.equals( propertyName ) ) { setVisualPadding( c, getPaddingFunction.apply( c ) ); break; } diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleClasses.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleClasses.java new file mode 100644 index 00000000..d96036f1 --- /dev/null +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleClasses.java @@ -0,0 +1,448 @@ +/* + * Copyright 2021 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.ui; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import java.awt.Color; +import java.awt.Dimension; +import javax.swing.*; +import javax.swing.table.JTableHeader; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import com.formdev.flatlaf.FlatClientProperties; +import com.formdev.flatlaf.FlatSystemProperties; + +/** + * @author Karl Tauber + */ +public class TestFlatStyleClasses +{ + private static final String BUTTON_PRIMARY = "borderColor: #08f; background: #08f; foreground: #fff"; + private static final String SECONDARY = "borderColor: #0f8; background: #0f8"; + private static final String TOGGLE_BUTTON_SECONDARY = "selectedBackground: #f00"; + private static final String BACKGROUND = "background: #f0f"; + + @BeforeAll + static void setup() { + System.setProperty( FlatSystemProperties.UI_SCALE_ENABLED, "false" ); + TestUtils.setup( false ); + + UIManager.put( "[style]Button.primary", BUTTON_PRIMARY ); + UIManager.put( "[style].secondary", SECONDARY ); + UIManager.put( "[style]ToggleButton.secondary", TOGGLE_BUTTON_SECONDARY ); + UIManager.put( "[style].test", BACKGROUND ); + + UIManager.put( "[style]Button.test", "foreground: #000001" ); + UIManager.put( "[style]CheckBox.test", "foreground: #000002" ); + UIManager.put( "[style]ComboBox.test", "foreground: #000003" ); + UIManager.put( "[style]EditorPane.test", "foreground: #000004" ); + UIManager.put( "[style]FormattedTextField.test", "foreground: #000005" ); + UIManager.put( "[style]InternalFrame.test", "foreground: #000006" ); + UIManager.put( "[style]Label.test", "foreground: #000007" ); + UIManager.put( "[style]List.test", "foreground: #000008" ); + UIManager.put( "[style]MenuBar.test", "foreground: #000009" ); + UIManager.put( "[style]Menu.test", "foreground: #000010" ); + UIManager.put( "[style]MenuItem.test", "foreground: #000011" ); + UIManager.put( "[style]CheckBoxMenuItem.test", "foreground: #000012" ); + UIManager.put( "[style]RadioButtonMenuItem.test", "foreground: #000013" ); + UIManager.put( "[style]PasswordField.test", "foreground: #000014" ); + UIManager.put( "[style]PopupMenu.test", "foreground: #000015" ); + UIManager.put( "[style]PopupMenuSeparator.test", "foreground: #000016" ); + UIManager.put( "[style]ProgressBar.test", "foreground: #000017" ); + UIManager.put( "[style]RadioButton.test", "foreground: #000018" ); + UIManager.put( "[style]ScrollBar.test", "foreground: #000019" ); + UIManager.put( "[style]ScrollPane.test", "foreground: #000020" ); + UIManager.put( "[style]Separator.test", "foreground: #000021" ); + UIManager.put( "[style]Slider.test", "foreground: #000022" ); + UIManager.put( "[style]Spinner.test", "foreground: #000023" ); + UIManager.put( "[style]SplitPane.test", "foreground: #000024" ); + UIManager.put( "[style]TabbedPane.test", "foreground: #000025" ); + UIManager.put( "[style]Table.test", "foreground: #000026" ); + UIManager.put( "[style]TableHeader.test", "foreground: #000027" ); + UIManager.put( "[style]TextArea.test", "foreground: #000028" ); + UIManager.put( "[style]TextField.test", "foreground: #000029" ); + UIManager.put( "[style]TextPane.test", "foreground: #000030" ); + UIManager.put( "[style]ToggleButton.test", "foreground: #000031" ); + UIManager.put( "[style]ToolBar.test", "foreground: #000032" ); + UIManager.put( "[style]Tree.test", "foreground: #000033" ); + + // for shared UIs + UIManager.put( "[style]Button.test2", "foreground: #000100" ); + UIManager.put( "[style]CheckBox.test2", "foreground: #000200" ); + UIManager.put( "[style]Label.test2", "foreground: #000700" ); + UIManager.put( "[style]PopupMenuSeparator.test2", "foreground: #001600" ); + UIManager.put( "[style]RadioButton.test2", "foreground: #001800" ); + UIManager.put( "[style]Separator.test2", "foreground: #002100" ); + UIManager.put( "[style]ToggleButton.test2", "foreground: #003100" ); + + // JToolBar.Separator + UIManager.put( "[style]ToolBarSeparator.toolbar-separator-test", "separatorWidth: 21" ); + UIManager.put( "[style]ToolBarSeparator.toolbar-separator-test2", "separatorWidth: 31" ); + } + + @AfterAll + static void cleanup() { + TestUtils.cleanup(); + System.clearProperty( FlatSystemProperties.UI_SCALE_ENABLED ); + } + + @Test + void styleForClass() { + assertEquals( null, FlatStylingSupport.getStyleForClasses( "foo", "Button" ) ); + + assertEquals( BUTTON_PRIMARY, FlatStylingSupport.getStyleForClasses( "primary", "Button" ) ); + assertEquals( SECONDARY, FlatStylingSupport.getStyleForClasses( "secondary", "Button" ) ); + + assertEquals( + FlatStylingSupport.concatStyles( SECONDARY, TOGGLE_BUTTON_SECONDARY ), + FlatStylingSupport.getStyleForClasses( "secondary", "ToggleButton" ) ); + + assertEquals( + FlatStylingSupport.concatStyles( BUTTON_PRIMARY, SECONDARY ), + FlatStylingSupport.getStyleForClasses( new String[] { "primary", "secondary" }, "Button" ) ); + assertEquals( + FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ), + FlatStylingSupport.getStyleForClasses( new String[] { "secondary", "primary" }, "Button" ) ); + } + + @Test + void apply1() { + JButton c = new JButton(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "primary" ); + + assertEquals( new Color( 0x0088ff ), c.getBackground() ); + assertEquals( Color.white, c.getForeground() ); + } + + @Test + void apply2() { + JButton c = new JButton(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, new String[] { "primary", "secondary" } ); + + assertEquals( new Color( 0x00ff88 ), c.getBackground() ); + assertEquals( Color.white, c.getForeground() ); + } + + @Test + void apply3() { + JButton c = new JButton(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, new String[] { "secondary", "primary" } ); + + assertEquals( new Color( 0x0088ff ), c.getBackground() ); + assertEquals( Color.white, c.getForeground() ); + } + + //---- components --------------------------------------------------------- + + @Test + void button() { + JButton c = new JButton(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000001 ), c.getForeground() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" ); + assertEquals( new Color( 0x000100 ), c.getForeground() ); + } + + @Test + void checkBox() { + JCheckBox c = new JCheckBox(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000002 ), c.getForeground() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" ); + assertEquals( new Color( 0x000200 ), c.getForeground() ); + } + + @Test + void comboBox() { + JComboBox c = new JComboBox<>(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000003 ), c.getForeground() ); + } + + @Test + void editorPane() { + JEditorPane c = new JEditorPane(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000004 ), c.getForeground() ); + } + + @Test + void formattedTextField() { + JFormattedTextField c = new JFormattedTextField(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000005 ), c.getForeground() ); + } + + @Test + void internalFrame() { + JInternalFrame c = new JInternalFrame(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000006 ), c.getForeground() ); + } + + @Test + void label() { + JLabel c = new JLabel(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000007 ), c.getForeground() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" ); + assertEquals( new Color( 0x000700 ), c.getForeground() ); + } + + @Test + void list() { + JList c = new JList<>(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000008 ), c.getForeground() ); + } + + @Test + void menuBar() { + JMenuBar c = new JMenuBar(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000009 ), c.getForeground() ); + } + + @Test + void menu() { + JMenu c = new JMenu(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000010 ), c.getForeground() ); + } + + @Test + void menuItem() { + JMenuItem c = new JMenuItem(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000011 ), c.getForeground() ); + } + + @Test + void checkBoxMenuItem() { + JCheckBoxMenuItem c = new JCheckBoxMenuItem(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000012 ), c.getForeground() ); + } + + @Test + void radioButtonMenuItem() { + JRadioButtonMenuItem c = new JRadioButtonMenuItem(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000013 ), c.getForeground() ); + } + + @Test + void passwordField() { + JPasswordField c = new JPasswordField(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000014 ), c.getForeground() ); + } + + @Test + void popupMenu() { + JPopupMenu c = new JPopupMenu(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000015 ), c.getForeground() ); + } + + @Test + void popupMenuSeparator() { + JPopupMenu.Separator c = new JPopupMenu.Separator(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000016 ), c.getForeground() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" ); + assertEquals( new Color( 0x001600 ), c.getForeground() ); + } + + @Test + void progressBar() { + JProgressBar c = new JProgressBar(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000017 ), c.getForeground() ); + } + + @Test + void radioButton() { + JRadioButton c = new JRadioButton(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000018 ), c.getForeground() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" ); + assertEquals( new Color( 0x001800 ), c.getForeground() ); + } + + @Test + void scrollBar() { + JScrollBar c = new JScrollBar(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000019 ), c.getForeground() ); + } + + @Test + void scrollPane() { + JScrollPane c = new JScrollPane(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000020 ), c.getForeground() ); + } + + @Test + void separator() { + JSeparator c = new JSeparator(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000021 ), c.getForeground() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" ); + assertEquals( new Color( 0x002100 ), c.getForeground() ); + } + + @Test + void slider() { + JSlider c = new JSlider(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000022 ), c.getForeground() ); + } + + @Test + void spinner() { + JSpinner c = new JSpinner(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000023 ), c.getForeground() ); + } + + @Test + void splitPane() { + JSplitPane c = new JSplitPane(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000024 ), c.getForeground() ); + } + + @Test + void tabbedPane() { + JTabbedPane c = new JTabbedPane(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000025 ), c.getForeground() ); + } + + @Test + void table() { + JTable c = new JTable(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000026 ), c.getForeground() ); + } + + @Test + void tableHeader() { + JTableHeader c = new JTableHeader(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000027 ), c.getForeground() ); + } + + @Test + void textArea() { + JTextArea c = new JTextArea(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000028 ), c.getForeground() ); + } + + @Test + void textField() { + JTextField c = new JTextField(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000029 ), c.getForeground() ); + } + + @Test + void textPane() { + JTextPane c = new JTextPane(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000030 ), c.getForeground() ); + } + + @Test + void toggleButton() { + JToggleButton c = new JToggleButton(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000031 ), c.getForeground() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test2" ); + assertEquals( new Color( 0x003100 ), c.getForeground() ); + } + + @Test + void toolBar() { + JToolBar c = new JToolBar(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000032 ), c.getForeground() ); + } + + @Test + void toolBarSeparator() { + JToolBar.Separator c = new JToolBar.Separator(); + assertEquals( new Dimension( 0, 7 ), c.getPreferredSize() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "toolbar-separator-test" ); + assertEquals( new Dimension( 0, 21 ), c.getPreferredSize() ); + + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "toolbar-separator-test2" ); + assertEquals( new Dimension( 0, 31 ), c.getPreferredSize() ); + } + + @Test + void tree() { + JTree c = new JTree(); + c.putClientProperty( FlatClientProperties.STYLE_CLASS, "test" ); + assertEquals( Color.magenta, c.getBackground() ); + assertEquals( new Color( 0x000033 ), c.getForeground() ); + } +}