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 367858c9..4c3f42ea 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
@@ -830,6 +830,7 @@ class UIDefaultsLoader
try {
switch( function ) {
case "if": return parseColorIf( value, params, resolver );
+ case "lazy": return parseColorLazy( value, params, resolver );
case "systemColor": return parseColorSystemColor( value, params, resolver );
case "rgb": return parseColorRgbOrRgba( false, params, resolver );
case "rgba": return parseColorRgbOrRgba( true, params, resolver );
@@ -877,6 +878,32 @@ class UIDefaultsLoader
return parseColorOrFunction( resolver.apply( ifValue ), resolver );
}
+ /**
+ * Syntax: lazy(uiKey)
+ *
+ * This "lazy" function is only used if the "lazy" is passed as parameter to another
+ * color function. Otherwise, the general "lazy" function is used.
+ *
+ * Note: The color is resolved immediately, not lazy, because it is passed as parameter to another color function.
+ * So e.g. {@code darken(lazy(List.background), 10%)} is the same as {@code darken($List.background, 10%)}.
+ *
+ * Only useful if a property is defined as lazy and that property is used
+ * in another property's color function. E.g.
+ *
+ *
{@code
+ * someProperty = lazy(List.background)
+ * anotherProperty = darken($someProperty, 10%)
+ * }
+ */
+ private static Object parseColorLazy( String value, List params, Function resolver )
+ throws IllegalArgumentException
+ {
+ if( params.size() != 1 )
+ throw newMissingParametersException( value );
+
+ return parseColorOrFunction( resolver.apply( PROPERTY_PREFIX + params.get( 0 ) ), resolver );
+ }
+
/**
* Syntax: systemColor(name[,defaultValue])
* - name: system color name
@@ -974,7 +1001,7 @@ class UIDefaultsLoader
* fadein(color,amount[,options]) or fadeout(color,amount[,options])
* - color: a color (e.g. #f00) or a color function
* - amount: percentage 0-100%
- * - options: [relative] [autoInverse] [noAutoInverse] [lazy] [derived]
+ * - options: [relative] [autoInverse] [noAutoInverse] [derived] [lazy]
*/
private static Object parseColorHSLIncreaseDecrease( int hslIndex, boolean increase,
List params, Function resolver )
@@ -984,15 +1011,15 @@ class UIDefaultsLoader
int amount = parsePercentage( params.get( 1 ) );
boolean relative = false;
boolean autoInverse = false;
- boolean lazy = false;
boolean derived = false;
+ boolean lazy = false;
if( params.size() > 2 ) {
String options = params.get( 2 );
relative = options.contains( "relative" );
autoInverse = options.contains( "autoInverse" );
- lazy = options.contains( "lazy" );
derived = options.contains( "derived" );
+ lazy = options.contains( "lazy" );
// use autoInverse by default for derived colors, except if noAutoInverse is set
if( derived && !options.contains( "noAutoInverse" ) )
@@ -1003,14 +1030,8 @@ class UIDefaultsLoader
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease(
hslIndex, increase, amount, relative, autoInverse );
- if( lazy ) {
- return (LazyValue) t -> {
- Object color = lazyUIManagerGet( colorStr );
- return (color instanceof Color)
- ? new ColorUIResource( ColorFunctions.applyFunctions( (Color) color, function ) )
- : null;
- };
- }
+ if( lazy )
+ return newLazyColorFunction( colorStr, function );
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver );
@@ -1039,14 +1060,8 @@ class UIDefaultsLoader
// create function
ColorFunction function = new ColorFunctions.Fade( amount );
- if( lazy ) {
- return (LazyValue) t -> {
- Object color = lazyUIManagerGet( colorStr );
- return (color instanceof Color)
- ? new ColorUIResource( ColorFunctions.applyFunctions( (Color) color, function ) )
- : null;
- };
- }
+ if( lazy )
+ return newLazyColorFunction( colorStr, function );
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver );
@@ -1056,7 +1071,7 @@ class UIDefaultsLoader
* Syntax: spin(color,angle[,options])
* - color: a color (e.g. #f00) or a color function
* - angle: number of degrees to rotate
- * - options: [derived]
+ * - options: [derived] [lazy]
*/
private static Object parseColorSpin( List params, Function resolver )
throws IllegalArgumentException
@@ -1064,15 +1079,20 @@ class UIDefaultsLoader
String colorStr = params.get( 0 );
int amount = parseInteger( params.get( 1 ) );
boolean derived = false;
+ boolean lazy = false;
if( params.size() > 2 ) {
String options = params.get( 2 );
derived = options.contains( "derived" );
+ lazy = options.contains( "lazy" );
}
// create function
ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false );
+ if( lazy )
+ return newLazyColorFunction( colorStr, function );
+
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver );
}
@@ -1084,7 +1104,7 @@ class UIDefaultsLoader
* changeAlpha(color,value[,options])
* - color: a color (e.g. #f00) or a color function
* - value: for hue: number of degrees; otherwise: percentage 0-100%
- * - options: [derived]
+ * - options: [derived] [lazy]
*/
private static Object parseColorChange( int hslIndex,
List params, Function resolver )
@@ -1095,15 +1115,20 @@ class UIDefaultsLoader
? parseInteger( params.get( 1 ) )
: parsePercentage( params.get( 1 ) );
boolean derived = false;
+ boolean lazy = false;
if( params.size() > 2 ) {
String options = params.get( 2 );
derived = options.contains( "derived" );
+ lazy = options.contains( "lazy" );
}
// create function
ColorFunction function = new ColorFunctions.HSLChange( hslIndex, value );
+ if( lazy )
+ return newLazyColorFunction( colorStr, function );
+
// parse base color, apply function and create derived color
return parseFunctionBaseColor( colorStr, function, derived, resolver );
}
@@ -1116,7 +1141,7 @@ class UIDefaultsLoader
* - color2: a color (e.g. #f00) or a color function
* - weight: the weight (in range 0-100%) to mix the two colors
* larger weight uses more of first color, smaller weight more of second color
- * - options: [derived]
+ * - options: [derived] [lazy]
*/
private static Object parseColorMix( String color1Str, List params, Function resolver )
throws IllegalArgumentException
@@ -1127,6 +1152,7 @@ class UIDefaultsLoader
String color2Str = params.get( i++ );
int weight = 50;
boolean derived = false;
+ boolean lazy = false;
if( params.size() > i ) {
String weightStr = params.get( i );
@@ -1138,6 +1164,7 @@ class UIDefaultsLoader
if( params.size() > i ) {
String options = params.get( i );
derived = options.contains( "derived" );
+ lazy = options.contains( "lazy" );
}
// parse second color
@@ -1148,6 +1175,9 @@ class UIDefaultsLoader
// create function
ColorFunction function = new ColorFunctions.Mix2( color1, weight );
+ if( lazy )
+ return newLazyColorFunction( color2Str, function );
+
// parse first color, apply function and create mixed color
return parseFunctionBaseColor( color2Str, function, derived, resolver );
}
@@ -1243,6 +1273,15 @@ class UIDefaultsLoader
return new ColorUIResource( newColor );
}
+ private static LazyValue newLazyColorFunction( String uiKey, ColorFunction function ) {
+ return (LazyValue) t -> {
+ Object color = lazyUIManagerGet( uiKey );
+ return (color instanceof Color)
+ ? new ColorUIResource( ColorFunctions.applyFunctions( (Color) color, function ) )
+ : null;
+ };
+ }
+
/**
* Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [|+|-|%] [family[, family]] [$baseFontKey]
*/
diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java
index 73f75419..28c36c89 100644
--- a/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java
+++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java
@@ -272,9 +272,54 @@ public class TestUIDefaultsLoader
}
@Test
- void parseDerivedColorFunctions() {
- // lighten, darken
+ void parseLazyColorFunctions() {
+ // lighten
+ assertEquals( new Color( 0xff6666 ), parseColorLazy( "lighten(dummyColor, 20%, lazy)", new Color( 0xff0000 ) ) );
+ // darken
+ assertEquals( new Color( 0x990000 ), parseColorLazy( "darken(dummyColor, 20%, lazy)", new Color( 0xff0000 ) ) );
+
+ // saturate
+ assertEquals( new Color( 0xf32e2e ), parseColorLazy( "saturate(dummyColor, 20%, lazy)", new Color( 0xdd4444 ) ) );
+
+ // desaturate
+ assertEquals( new Color( 0x745858 ), parseColorLazy( "desaturate(dummyColor, 20%, lazy)", new Color( 0x884444 ) ) );
+
+ // fadein
+ assertEquals( new Color( 0xddff0000, true ), parseColorLazy( "fadein(dummyColor, 20%, lazy)", new Color( 0xaaff0000, true ) ) );
+
+ // fadeout
+ assertEquals( new Color( 0x11ff0000, true ), parseColorLazy( "fadeout(dummyColor, 20%, lazy)", new Color( 0x44ff0000, true ) ) );
+
+ // fade
+ assertEquals( new Color( 0x33ff0000, true ), parseColorLazy( "fade(dummyColor, 20%, lazy)", new Color( 0xff0000 ) ) );
+ assertEquals( new Color( 0xccff0000, true ), parseColorLazy( "fade(dummyColor, 80%, lazy)", new Color( 0x10ff0000, true ) ) );
+
+ // spin
+ assertEquals( new Color( 0xffaa00 ), parseColorLazy( "spin(dummyColor, 40, lazy)", new Color( 0xff0000 ) ) );
+ assertEquals( new Color( 0xff00aa ), parseColorLazy( "spin(dummyColor, -40, lazy)", new Color( 0xff0000 ) ) );
+
+ // changeHue / changeSaturation / changeLightness / changeAlpha
+ assertEquals( new Color( 0xffaa00 ), parseColorLazy( "changeHue(dummyColor, 40, lazy)", new Color( 0xff0000 ) ) );
+ assertEquals( new Color( 0xb34d4d ), parseColorLazy( "changeSaturation(dummyColor, 40%, lazy)", new Color( 0xff0000 ) ) );
+ assertEquals( new Color( 0xcc0000 ), parseColorLazy( "changeLightness(dummyColor, 40%, lazy)", new Color( 0xff0000 ) ) );
+ assertEquals( new Color( 0x66ff0000, true ), parseColorLazy( "changeAlpha(dummyColor, 40%, lazy)", new Color( 0xff0000 ) ) );
+
+ // mix
+ assertEquals( new Color( 0x808000 ), parseColorLazy( "mix(#f00, dummyColor, lazy)", new Color( 0x00ff00 ) ) );
+ assertEquals( new Color( 0xbf4000 ), parseColorLazy( "mix(#f00, dummyColor, 75%, lazy)", new Color( 0x00ff00 ) ) );
+
+ // tint
+ assertEquals( new Color( 0xff80ff ), parseColorLazy( "tint(dummyColor, lazy)", new Color( 0xff00ff ) ) );
+ assertEquals( new Color( 0xffbfff ), parseColorLazy( "tint(dummyColor, 75%, lazy)", new Color( 0xff00ff ) ) );
+
+ // shade
+ assertEquals( new Color( 0x800080 ), parseColorLazy( "shade(dummyColor, lazy)", new Color( 0xff00ff ) ) );
+ assertEquals( new Color( 0x400040 ), parseColorLazy( "shade(dummyColor, 75%, lazy)", new Color( 0xff00ff ) ) );
+ }
+
+ @Test
+ void parseDerivedColorFunctions() {
// mix
assertDerivedColorEquals( new Color( 0x808000 ), "mix(#f00, #0f0, derived)", new Mix2( Color.red, 50 ) );
assertDerivedColorEquals( new Color( 0xbf4000 ), "mix(#f00, #0f0, 75%, derived)", new Mix2( Color.red, 75 ) );
@@ -400,6 +445,13 @@ public class TestUIDefaultsLoader
return UIDefaultsLoader.parseValue( "dummyColor", value, null );
}
+ private Object parseColorLazy( String value, Color actual ) {
+ UIManager.put( "dummyColor", actual );
+ Object v = UIDefaultsLoader.parseValue( "dummyColor", value, null );
+ assertInstanceOf( LazyValue.class, v );
+ return ((LazyValue)v).createValue( null );
+ }
+
//---- class TestInstance -------------------------------------------------
@SuppressWarnings( "EqualsHashCode" ) // Error Prone