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 82e77001..9ff1ff0a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -928,6 +928,11 @@ public abstract class FlatLaf * Registers a UI defaults getter function that is invoked before the standard getter. * This allows using different UI defaults for special purposes * (e.g. using multiple themes at the same time). + *

+ * The key is passed as parameter to the function. + * If the function returns {@code null}, then the next registered function is invoked. + * If all registered functions return {@code null}, then the current look and feel is asked. + * If the function returns {@link #NULL_VALUE}, then the UI value becomes {@code null}. * * @see #unregisterUIDefaultsGetter(Function) * @see #runWithUIDefaultsGetter(Function, Runnable) @@ -969,6 +974,25 @@ public abstract class FlatLaf * (e.g. using multiple themes at the same time). * If the current look and feel is not FlatLaf, then the getter is ignored and * the given runnable invoked. + *

+ * The key is passed as parameter to the function. + * If the function returns {@code null}, then the next registered function is invoked. + * If all registered functions return {@code null}, then the current look and feel is asked. + * If the function returns {@link #NULL_VALUE}, then the UI value becomes {@code null}. + *

+ * Example: + *

{@code
+	 * // create secondary theme
+	 * UIDefaults darkDefaults = new FlatDarkLaf().getDefaults();
+	 *
+	 * // create panel using secondary theme
+	 * FlatLaf.runWithUIDefaultsGetter( key -> {
+	 *     Object value = darkDefaults.get( key );
+	 *     return (value != null) ? value : FlatLaf.NULL_VALUE;
+	 * }, () -> {
+	 *     // TODO create components that should use secondary theme here
+	 * } );
+	 * }
* * @see #registerUIDefaultsGetter(Function) * @see #unregisterUIDefaultsGetter(Function) @@ -987,6 +1011,17 @@ public abstract class FlatLaf runnable.run(); } + /** + * Special value returned by functions used in {@link #runWithUIDefaultsGetter(Function, Runnable)} + * or {@link #registerUIDefaultsGetter(Function)} to indicate that the UI value should + * become {@code null}. + * + * @see #runWithUIDefaultsGetter(Function, Runnable) + * @see #registerUIDefaultsGetter(Function) + * @since 1.6 + */ + public static final Object NULL_VALUE = new Object(); + //---- class FlatUIDefaults ----------------------------------------------- private class FlatUIDefaults @@ -999,13 +1034,13 @@ public abstract class FlatLaf @Override public Object get( Object key ) { Object value = getValue( key ); - return (value != null) ? value : super.get( key ); + return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key ); } @Override public Object get( Object key, Locale l ) { Object value = getValue( key ); - return (value != null) ? value : super.get( key, l ); + return (value != null) ? (value != NULL_VALUE ? value : null) : super.get( key, l ); } private Object getValue( Object key ) { diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePreview.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePreview.java index be8a567c..e2625a24 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePreview.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePreview.java @@ -161,6 +161,17 @@ class FlatThemePreview value = ((ActiveValue)value).createValue( null ); // System.out.println( key + " = " + value ); + + // If value is null and is a property that is defined in a core theme, + // then force the value to null. + // This is necessary for cases where the current application Laf defines a property + // but the edited theme does not (or has set the value explicitly to null). + // E.g. FlatLightLaf defines Button.focusedBackground, but in FlatDarkLaf + // it is not defined. Without this code, the preview for FlatDarkLaf would use + // Button.focusedBackground from FlatLightLaf if FlatLightLaf is the current application Laf. + if( value == null && FlatThemePropertiesBaseManager.getDefindedCoreKeys().contains( key ) ) + return FlatLaf.NULL_VALUE; + return value; } diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesBaseManager.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesBaseManager.java index 4f77a689..72d7a839 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesBaseManager.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesBaseManager.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -47,7 +48,8 @@ class FlatThemePropertiesBaseManager }; private final Map providers = new HashMap<>(); - private Map coreThemes; + private static Map coreThemes; + private static Set definedCoreKeys; FlatThemePropertiesSupport.BasePropertyProvider create( File file, FlatThemePropertiesSupport propertiesSupport ) { String name = StringUtils.removeTrailing( file.getName(), ".properties" ); @@ -61,7 +63,31 @@ class FlatThemePropertiesBaseManager providers.clear(); } - private void loadCoreThemes() { + static Set getDefindedCoreKeys() { + if( definedCoreKeys != null ) + return definedCoreKeys; + + loadCoreThemes(); + + definedCoreKeys = new HashSet<>(); + for( Properties properties : coreThemes.values() ) { + for( Object k : properties.keySet() ) { + String key = (String) k; + if( key.startsWith( "*." ) || key.startsWith( "@" ) ) + continue; + if( key.startsWith( "[" ) ) { + int closeIndex = key.indexOf( ']' ); + if( closeIndex < 0 ) + continue; + key = key.substring( closeIndex + 1 ); + } + definedCoreKeys.add( key ); + } + } + return definedCoreKeys; + } + + private static void loadCoreThemes() { if( coreThemes != null ) return;