From 0101171159c79b318a51ca974c13c80101c67d8c Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Thu, 19 Nov 2020 11:31:38 +0100 Subject: [PATCH] UIDefaultsLoader: added fadein(), fadeout(), fade() and spin() color functions (inspired by Less CSS) --- .../com/formdev/flatlaf/UIDefaultsLoader.java | 64 ++++++++++++++++++- .../formdev/flatlaf/util/ColorFunctions.java | 52 +++++++++++---- .../formdev/flatlaf/FlatDarkLaf.properties | 2 +- .../com/formdev/flatlaf/FlatLaf.properties | 2 +- .../formdev/flatlaf/FlatLightLaf.properties | 2 +- .../uidefaults/FlatLightLaf_1.8.0_202.txt | 2 +- .../testing/uidefaults/UIDefaultsDump.java | 8 ++- .../themeeditor/FlatCompletionProvider.java | 14 +++- .../theme-editor-test.properties | 9 +++ 9 files changed, 135 insertions(+), 20 deletions(-) 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 adc6e177..6a009b73 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java @@ -586,13 +586,17 @@ class UIDefaultsLoader case "darken": return parseColorHSLIncreaseDecrease( 2, false, params, resolver, reportError ); case "saturate": return parseColorHSLIncreaseDecrease( 1, true, params, resolver, reportError ); case "desaturate": return parseColorHSLIncreaseDecrease( 1, false, params, resolver, reportError ); + case "fadein": return parseColorHSLIncreaseDecrease( 3, true, params, resolver, reportError ); + case "fadeout": return parseColorHSLIncreaseDecrease( 3, false, params, resolver, reportError ); + case "fade": return parseColorFade( params, resolver, reportError ); + case "spin": return parseColorSpin( params, resolver, reportError ); } throw new IllegalArgumentException( "unknown color function '" + value + "'" ); } /** - * Syntax: rgb(red,green,blue) or rgba(red,green,blue,alpha) or rgba(color,alpha) + * Syntax: rgb(red,green,blue) or rgba(red,green,blue,alpha) * - red: an integer 0-255 or a percentage 0-100% * - green: an integer 0-255 or a percentage 0-100% * - blue: an integer 0-255 or a percentage 0-100% @@ -603,6 +607,8 @@ class UIDefaultsLoader { if( hasAlpha && params.size() == 2 ) { // syntax rgba(color,alpha), which allows adding alpha to any color + // NOTE: this syntax is deprecated + // use fade(color,alpha) instead String colorStr = params.get( 0 ); int alpha = parseInteger( params.get( 1 ), 0, 255, true ); @@ -639,7 +645,8 @@ class UIDefaultsLoader /** * Syntax: lighten(color,amount[,options]) or darken(color,amount[,options]) or - * saturate(color,amount[,options]) or desaturate(color,amount[,options]) + * saturate(color,amount[,options]) or desaturate(color,amount[,options]) or + * 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] @@ -679,6 +686,59 @@ class UIDefaultsLoader }; } + // parse base color, apply function and create derived color + return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError ); + } + + /** + * Syntax: fade(color,amount[,options]) + * - color: a color (e.g. #f00) or a color function + * - amount: percentage 0-100% + * - options: [derived] + */ + private static Object parseColorFade( List params, Function resolver, boolean reportError ) { + String colorStr = params.get( 0 ); + int amount = parsePercentage( params.get( 1 ) ); + boolean derived = false; + + if( params.size() > 2 ) { + String options = params.get( 2 ); + derived = options.contains( "derived" ); + } + + // create function + ColorFunction function = new ColorFunctions.Fade( amount ); + + // parse base color, apply function and create derived color + return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError ); + } + + /** + * Syntax: spin(color,angle[,options]) + * - color: a color (e.g. #f00) or a color function + * - angle: number of degrees to rotate + * - options: [derived] + */ + private static Object parseColorSpin( List params, Function resolver, boolean reportError ) { + String colorStr = params.get( 0 ); + int amount = parseInteger( params.get( 1 ), true ); + boolean derived = false; + + if( params.size() > 2 ) { + String options = params.get( 2 ); + derived = options.contains( "derived" ); + } + + // create function + ColorFunction function = new ColorFunctions.HSLIncreaseDecrease( 0, true, amount, false, false ); + + // parse base color, apply function and create derived color + return parseFunctionBaseColor( colorStr, function, derived, resolver, reportError ); + } + + private static Object parseFunctionBaseColor( String colorStr, ColorFunction function, + boolean derived, Function resolver, boolean reportError ) + { // parse base color String resolvedColorStr = resolver.apply( colorStr ); ColorUIResource baseColor = (ColorUIResource) parseColorOrFunction( resolvedColorStr, resolver, reportError ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ColorFunctions.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ColorFunctions.java index 471dd7c0..4996ba75 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ColorFunctions.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ColorFunctions.java @@ -28,11 +28,12 @@ public class ColorFunctions public static Color applyFunctions( Color color, ColorFunction... functions ) { float[] hsl = HSLColor.fromRGB( color ); float alpha = color.getAlpha() / 255f; + float[] hsla = { hsl[0], hsl[1], hsl[2], alpha * 100 }; for( ColorFunction function : functions ) - function.apply( hsl ); + function.apply( hsla ); - return HSLColor.toRGB( hsl, alpha ); + return HSLColor.toRGB( hsla[0], hsla[1], hsla[2], hsla[3] / 100 ); } public static float clamp( float value ) { @@ -46,13 +47,13 @@ public class ColorFunctions //---- interface ColorFunction -------------------------------------------- public interface ColorFunction { - void apply( float[] hsl ); + void apply( float[] hsla ); } //---- class HSLIncreaseDecrease ------------------------------------------ /** - * Increase or decrease hue, saturation or luminance of a color in the HSL color space + * Increase or decrease hue, saturation, luminance or alpha of a color in the HSL color space * by an absolute or relative amount. */ public static class HSLIncreaseDecrease @@ -75,18 +76,45 @@ public class ColorFunctions } @Override - public void apply( float[] hsl ) { + public void apply( float[] hsla ) { float amount2 = increase ? amount : -amount; - amount2 = autoInverse && shouldInverse( hsl ) ? -amount2 : amount2; - hsl[hslIndex] = clamp( relative - ? (hsl[hslIndex] * ((100 + amount2) / 100)) - : (hsl[hslIndex] + amount2) ); + + if( hslIndex == 0 ) { + // hue is range 0-360 + hsla[0] = (hsla[0] + amount2) % 360; + return; + } + + amount2 = autoInverse && shouldInverse( hsla ) ? -amount2 : amount2; + hsla[hslIndex] = clamp( relative + ? (hsla[hslIndex] * ((100 + amount2) / 100)) + : (hsla[hslIndex] + amount2) ); } - protected boolean shouldInverse( float[] hsl ) { + protected boolean shouldInverse( float[] hsla ) { return increase - ? hsl[hslIndex] >= 50 - : hsl[hslIndex] < 50; + ? hsla[hslIndex] >= 50 + : hsla[hslIndex] < 50; + } + } + + //---- class HSLIncreaseDecrease ------------------------------------------ + + /** + * Set the alpha of a color. + */ + public static class Fade + implements ColorFunction + { + public final float amount; + + public Fade( float amount ) { + this.amount = amount; + } + + @Override + public void apply( float[] hsla ) { + hsla[3] = clamp( amount ); } } } diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties index 783f79ab..f3e13263 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties @@ -241,7 +241,7 @@ Slider.trackValueColor=#4A88C7 Slider.trackColor=#646464 Slider.thumbColor=$Slider.trackValueColor Slider.tickColor=#888 -Slider.focusedColor=rgba($Component.focusColor,80%) +Slider.focusedColor=fade($Component.focusColor,80%) Slider.hoverThumbColor=darken($Slider.thumbColor,10%,derived) Slider.pressedThumbColor=darken($Slider.thumbColor,15%,derived) Slider.disabledTrackColor=#4c5052 diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index d4597965..dbf91b85 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -682,7 +682,7 @@ TitlePane.foreground=@foreground TitlePane.inactiveForeground=@disabledText TitlePane.closeHoverBackground=#e81123 -TitlePane.closePressedBackground=rgba($TitlePane.closeHoverBackground,60%) +TitlePane.closePressedBackground=fade($TitlePane.closeHoverBackground,60%) TitlePane.closeHoverForeground=#fff TitlePane.closePressedForeground=#fff diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties index 5ad1e7b2..6d57c99d 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties @@ -253,7 +253,7 @@ Slider.trackValueColor=#1E82E6 Slider.trackColor=#c4c4c4 Slider.thumbColor=$Slider.trackValueColor Slider.tickColor=#888 -Slider.focusedColor=rgba($Component.focusColor,50%) +Slider.focusedColor=fade($Component.focusColor,50%) Slider.hoverThumbColor=lighten($Slider.thumbColor,10%,derived) Slider.pressedThumbColor=lighten($Slider.thumbColor,15%,derived) Slider.disabledTrackColor=#c0c0c0 diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt index 70bb803a..dc533773 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt @@ -851,7 +851,7 @@ Slider.disabledTrackColor #c0c0c0 javax.swing.plaf.ColorUIResource [UI] Slider.focus #9e9e9e javax.swing.plaf.ColorUIResource [UI] Slider.focusInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI] Slider.focusWidth 4 -Slider.focusedColor #7f97c3f3 javax.swing.plaf.ColorUIResource [UI] +Slider.focusedColor #8097c3f3 javax.swing.plaf.ColorUIResource [UI] Slider.font [active] $defaultFont [UI] Slider.foreground #000000 javax.swing.plaf.ColorUIResource [UI] Slider.highlight #ffffff javax.swing.plaf.ColorUIResource [UI] diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/uidefaults/UIDefaultsDump.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/uidefaults/UIDefaultsDump.java index ac36c871..d29490a5 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/uidefaults/UIDefaultsDump.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/uidefaults/UIDefaultsDump.java @@ -64,6 +64,7 @@ import com.formdev.flatlaf.intellijthemes.FlatAllIJThemes; import com.formdev.flatlaf.testing.FlatTestLaf; import com.formdev.flatlaf.ui.FlatLineBorder; import com.formdev.flatlaf.util.ColorFunctions.ColorFunction; +import com.formdev.flatlaf.util.ColorFunctions.Fade; import com.formdev.flatlaf.util.ColorFunctions.HSLIncreaseDecrease; import com.formdev.flatlaf.util.DerivedColor; import com.formdev.flatlaf.util.StringUtils; @@ -399,13 +400,18 @@ public class UIDefaultsDump HSLIncreaseDecrease func = (HSLIncreaseDecrease) function; String name; switch( func.hslIndex ) { - case 2: name = func.increase ? "lighten" : "darken"; break; + case 0: name = "spin"; break; case 1: name = func.increase ? "saturate" : "desaturate"; break; + case 2: name = func.increase ? "lighten" : "darken"; break; + case 3: name = func.increase ? "fadein" : "fadeout"; break; default: throw new IllegalArgumentException(); } out.printf( "%s(%.0f%%%s%s)", name, func.amount, (func.relative ? " relative" : ""), (func.autoInverse ? " autoInverse" : "") ); + } else if( function instanceof Fade ) { + Fade func = (Fade) function; + out.printf( "fade(%.0f%%)", func.amount ); } else throw new IllegalArgumentException( "unknown color function: " + function ); } diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatCompletionProvider.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatCompletionProvider.java index e709bc28..c26f9bde 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatCompletionProvider.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatCompletionProvider.java @@ -336,8 +336,9 @@ class FlatCompletionProvider "lightness", "0-100%", "alpha", "0-100%" ); + String colorParamDesc = "a color (e.g. #f00), a reference (e.g. $Other.key) or a color function"; String[] hslIncreaseDecreaseParams = { - "color", "a color (e.g. #f00), a reference (e.g. $Other.key) or a color function", + "color", colorParamDesc, "amount", "0-100%", "options", "(optional) [relative] [autoInverse] [noAutoInverse] [lazy] [derived]" }; @@ -345,6 +346,17 @@ class FlatCompletionProvider addFunction( "darken", hslIncreaseDecreaseParams ); addFunction( "saturate", hslIncreaseDecreaseParams ); addFunction( "desaturate", hslIncreaseDecreaseParams ); + addFunction( "fadein", hslIncreaseDecreaseParams ); + addFunction( "fadeout", hslIncreaseDecreaseParams ); + + addFunction( "fade", + "color", colorParamDesc, + "amount", "0-100%", + "options", "(optional) [derived]" ); + addFunction( "spin", + "color", colorParamDesc, + "angle", "number of degrees to rotate", + "options", "(optional) [derived]" ); } private void addFunction( String name, String... paramNamesAndDescs ) { diff --git a/flatlaf-theme-editor/theme-editor-test.properties b/flatlaf-theme-editor/theme-editor-test.properties index 889569e1..75ece812 100644 --- a/flatlaf-theme-editor/theme-editor-test.properties +++ b/flatlaf-theme-editor/theme-editor-test.properties @@ -40,3 +40,12 @@ Prop.colorFunc5=lighten(#fe1289,20%) Prop.colorFunc6=darken(#fe1289,20%) Prop.colorFunc7=lighten($Prop.colorFunc4,20%,relative autoInverse) Prop.colorFunc8=lighten(Prop.colorFunc4,20%,lazy) +Prop.colorFunc9=fadein(#ff000000,30%) +Prop.colorFunc10=fadeout(#ff0000,40%) +Prop.colorFunc11=fade(#ff0000,50%) + +Prop.colorFunc12=#f00 +Prop.colorFunc13=spin($Prop.colorFunc12,40) +Prop.colorFunc14=spin($Prop.colorFunc12,-40) +Prop.colorFunc15=spin($Prop.colorFunc12,400) +Prop.colorFunc16=spin($Prop.colorFunc12,-400)