From 08ca2aa26664258a1b2af4d1be674f78e5f3d75d Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 6 Sep 2021 22:48:39 +0200 Subject: [PATCH] Styling: - support references in color functions - added test for using color functions in styling --- .../java/com/formdev/flatlaf/FlatLaf.java | 4 +- .../com/formdev/flatlaf/UIDefaultsLoader.java | 19 +++++ .../flatlaf/ui/FlatStylingSupport.java | 2 + .../formdev/flatlaf/ui/TestFlatStyling.java | 72 +++++++++++++++++++ .../themeeditor/FlatThemeFileEditor.java | 4 +- .../themeeditor/FlatDarkLaf.properties | 5 -- .../themeeditor/FlatLightLaf.properties | 5 -- 7 files changed, 99 insertions(+), 12 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index 1d0caa2f..d9589d19 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -32,6 +32,7 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; @@ -796,7 +797,8 @@ public abstract class FlatLaf throws IllegalArgumentException { // parse value - Object val = UIDefaultsLoader.parseValue( key, value, valueType ); + Object val = UIDefaultsLoader.parseValue( key, value, valueType, null, + v -> UIDefaultsLoader.resolveValueFromUIManager( v ), Collections.emptyList() ); // create actual value if lazy or active if( val instanceof LazyValue ) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java index 7f157776..0edf48e4 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java @@ -290,6 +290,25 @@ class UIDefaultsLoader return resolveValue( newValue, propertiesGetter ); } + static String resolveValueFromUIManager( String value ) { + if( !value.startsWith( PROPERTY_PREFIX ) ) + return value; + + String key = value.substring( PROPERTY_PREFIX.length() ); + Object newValue = UIManager.get( key ); + if( newValue == null ) + throw new IllegalArgumentException( "property '" + key + "' not found" ); + + // convert binary color to string + if( newValue instanceof Color ) { + Color color = (Color) newValue; + int alpha = color.getAlpha(); + return String.format( (alpha != 255) ? "#%06x%02x" : "#%06x", color.getRGB() & 0xffffff, alpha ); + } + + throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" ); + } + enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY } 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 c3adab67..d66657e3 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 @@ -191,6 +191,7 @@ public class FlatStylingSupport } private static Object parseValue( String key, String value ) { + // simple reference if( value.startsWith( "$" ) ) return UIManager.get( value.substring( 1 ) ); @@ -199,6 +200,7 @@ public class FlatStylingSupport if( key.startsWith( "[" ) ) key = key.substring( key.indexOf( ']' ) + 1 ); + // parse string return FlatLaf.parseDefaultsValue( key, value, null ); } 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 8d36fdfc..5f3b99cd 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,6 +19,7 @@ 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.Dimension; import java.awt.Insets; import java.util.HashMap; import java.util.Map; @@ -64,6 +65,77 @@ public class TestFlatStyling FlatStylingSupport.parse( "background: #fff; foreground: #000; someWidth: 20" ) ); } + @Test + void parseColorFunctions() { + testColorStyle( 0x0c2238, "rgb(12,34,56)" ); + testColorStyle( 0x4e0c2238, "rgba(12,34,56,78)" ); + testColorStyle( 0xb57869, "hsl(12,34%,56%)" ); + testColorStyle( 0xc7b57869, "hsla(12,34%,56%,78%)" ); + + testColorStyle( 0xff6666, "lighten(#f00,20%)" ); + testColorStyle( 0x990000, "darken(#f00,20%)" ); + + testColorStyle( 0x9c3030, "saturate(#844,20%)" ); + testColorStyle( 0x745858, "desaturate(#844,20%)" ); + + testColorStyle( 0x4dff0000, "fadein(#ff000000,30%)" ); + testColorStyle( 0x99ff0000, "fadeout(#ff0000,40%)" ); + testColorStyle( 0x80ff0000, "fade(#ff0000,50%)" ); + + testColorStyle( 0xffaa00, "spin(#f00,40)" ); + testColorStyle( 0xff00aa, "spin(#f00,-40)" ); + + testColorStyle( 0x00ffff, "changeHue(#f00,180)" ); + testColorStyle( 0xbf4040, "changeSaturation(#f00,50%)" ); + testColorStyle( 0xff9999, "changeLightness(#f00,80%)" ); + testColorStyle( 0x80ff0000, "changeAlpha(#f00,50%)" ); + + testColorStyle( 0x1ae600, "mix(#f00,#0f0,10%)" ); + testColorStyle( 0x40bf00, "mix(#f00,#0f0,25%)" ); + testColorStyle( 0x808000, "mix(#f00,#0f0)" ); + testColorStyle( 0xbf4000, "mix(#f00,#0f0,75%)" ); + testColorStyle( 0xe61a00, "mix(#f00,#0f0,90%)" ); + + testColorStyle( 0xff40ff, "tint(#f0f,25%)" ); + testColorStyle( 0xff80ff, "tint(#f0f)" ); + testColorStyle( 0xffbfff, "tint(#f0f,75%)" ); + + testColorStyle( 0xbf00bf, "shade(#f0f,25%)" ); + testColorStyle( 0x800080, "shade(#f0f)" ); + testColorStyle( 0x400040, "shade(#f0f,75%)" ); + + // nested + testColorStyle( 0xd1c7c7, "saturate(darken(#fff,20%),10%)" ); + testColorStyle( 0xcf00cf, "shade(shade(#f0f,10%),10%)" ); + testColorStyle( 0xba00ba, "shade(shade(shade(#f0f,10%),10%),10%)" ); + } + + @Test + void parseReferences() { + assertEquals( Color.white, UIManager.getColor( "TextField.background" ) ); + + testColorStyle( 0xffffff, "$TextField.background" ); + testColorStyle( 0xcccccc, "darken($TextField.background,20%)" ); + testColorStyle( 0xd1c7c7, "saturate(darken($TextField.background,20%),10%)" ); + + testStyle( "hideMnemonics", true, "$Component.hideMnemonics" ); + testStyle( "arc", 6, "$Button.arc" ); + testStyle( "dropShadowOpacity", 0.15f, "$Popup.dropShadowOpacity" ); + testStyle( "margin", new Insets( 2, 14, 2, 14 ) , "$Button.margin" ); + testStyle( "iconSize", new Dimension( 64, 64 ), "$DesktopIcon.iconSize" ); + testStyle( "arrowType", "chevron", "$Component.arrowType" ); + } + + private void testColorStyle( int expectedRGB, String style ) { + testStyle( "background", new Color( expectedRGB, (expectedRGB & 0xff000000) != 0 ), style ); + } + + private void testStyle( String key, Object expected, String style ) { + assertEquals( + expectedMap( key, expected ), + FlatStylingSupport.parse( key + ": " + style ) ); + } + private Map expectedMap( Object... keyValuePairs ) { Map map = new HashMap<>(); for( int i = 0; i < keyValuePairs.length; i += 2 ) diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java index 14a3d253..b86fa60e 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java @@ -131,7 +131,9 @@ class FlatThemeFileEditor darkLafMenuItem.setSelected( true ); // highlight selected tab - tabbedPane.setStyle( "[light]selectedBackground: #fff; [dark]selectedBackground: #303234" ); + tabbedPane.setStyle( + "[light]selectedBackground: lighten($TabbedPane.background,5%);" + + " [dark]selectedBackground: darken($TabbedPane.background,5%)" ); // add "+" button to tabbed pane newButton = new JButton( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/add.svg" ) ); diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatDarkLaf.properties b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatDarkLaf.properties index 04e68e5d..d274c2e0 100644 --- a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatDarkLaf.properties +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatDarkLaf.properties @@ -14,11 +14,6 @@ # limitations under the License. # -#---- TabbedPane ---- - -#TabbedPane.selectedBackground = darken($TabbedPane.background,5%) - - #---- FlatThemeEditorPane ---- FlatThemeEditorPane.background = #2b2b2b diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLightLaf.properties b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLightLaf.properties index d84c0966..0678c339 100644 --- a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLightLaf.properties +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLightLaf.properties @@ -14,11 +14,6 @@ # limitations under the License. # -#---- TabbedPane ---- - -#TabbedPane.selectedBackground = lighten($TabbedPane.background,5%) - - #---- FlatThemeEditorPane ---- FlatThemeEditorPane.background = #fff