From 638af4bcd773df18807ae9e95c2ed5a80517da56 Mon Sep 17 00:00:00 2001 From: DUDSS Date: Thu, 8 Apr 2021 13:45:17 +0200 Subject: [PATCH 01/11] Added an option to specify an RGBImageFilter to a FlatSVGIcon --- .../formdev/flatlaf/extras/FlatRGBFilter.java | 23 ++++++++++++++++ .../formdev/flatlaf/extras/FlatSVGIcon.java | 26 +++++++++++++++++-- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatRGBFilter.java diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatRGBFilter.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatRGBFilter.java new file mode 100644 index 00000000..83c1917c --- /dev/null +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatRGBFilter.java @@ -0,0 +1,23 @@ +package com.formdev.flatlaf.extras; + +import java.awt.*; +import java.awt.image.RGBImageFilter; + +/** + * A simplified RGBImageFilter that presents individual rgba components as a Color object. + * Can be used to modify the color of a {@link FlatSVGIcon}- + */ +public abstract class FlatRGBFilter extends RGBImageFilter +{ + @Override + public int filterRGB(int x, int y, int rgb) { + return filterRGB(new Color(rgb)).getRGB(); + } + + /** + * @param c Original color + * @return Modified color + */ + public abstract Color filterRGB(Color c); +} + diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index ff7655b4..2951c8a3 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -66,6 +66,8 @@ public class FlatSVGIcon private final boolean disabled; private final ClassLoader classLoader; + private RGBImageFilter userFilter = null; + private SVGDiagram diagram; private boolean dark; @@ -168,6 +170,19 @@ public class FlatSVGIcon this.disabled = disabled; } + /** + * Sets an RGBImageFilter to be used when painting the icon. + * For simple RGB modifications you can use the {@link FlatRGBFilter}. + * @param filter + */ + public void setFilter(RGBImageFilter filter) { + this.userFilter = filter; + } + + public RGBImageFilter getFilter() { + return userFilter; + } + /** * Creates a new icon with given width and height, which is derived from this icon. * @@ -303,7 +318,7 @@ public class FlatSVGIcon : GrayFilter.createDisabledIconFilter( dark ); } - Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), grayFilter ); + Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), grayFilter, this.userFilter ); try { FlatUIUtils.setRenderingHints( g2 ); @@ -457,11 +472,13 @@ public class FlatSVGIcon { private final ColorFilter colorFilter; private final RGBImageFilter grayFilter; + private final RGBImageFilter userFilter; - public GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, RGBImageFilter grayFilter ) { + public GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, RGBImageFilter grayFilter, RGBImageFilter userFilter) { super( delegate ); this.colorFilter = colorFilter; this.grayFilter = grayFilter; + this.userFilter = userFilter; } @Override @@ -477,6 +494,11 @@ public class FlatSVGIcon } private Color filterColor( Color color ) { + if( userFilter != null ) { + int oldRGB = color.getRGB(); + int newRGB = userFilter.filterRGB( 0, 0, oldRGB ); + color = (newRGB != oldRGB) ? new Color( newRGB, true ) : color; + } if( colorFilter != null ) color = colorFilter.filter( color ); if( grayFilter != null ) { From ba0f43455b37a3594de05a59e7bc600afd7fb03e Mon Sep 17 00:00:00 2001 From: DUDSS Date: Fri, 9 Apr 2021 00:07:04 +0200 Subject: [PATCH 02/11] Reworked how the FlatSVGIcon filters work. Filters are now set using the ColorFilter class and can work globally too. Added related demo components to flatlaf-demo extras tab. --- .../flatlaf/demo/extras/ExtrasPanel.java | 65 ++++++++ .../formdev/flatlaf/extras/FlatRGBFilter.java | 23 --- .../formdev/flatlaf/extras/FlatSVGIcon.java | 152 +++++++++++++++--- 3 files changed, 197 insertions(+), 43 deletions(-) delete mode 100644 flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatRGBFilter.java diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java index 37cfec1f..9614920a 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java @@ -18,8 +18,10 @@ package com.formdev.flatlaf.demo.extras; import javax.swing.*; import com.formdev.flatlaf.extras.*; +import com.formdev.flatlaf.extras.FlatSVGIcon.ColorFilter; import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox; import net.miginfocom.swing.*; +import java.awt.*; /** * @author Karl Tauber @@ -27,6 +29,8 @@ import net.miginfocom.swing.*; public class ExtrasPanel extends JPanel { + public int counter = 0; + public ExtrasPanel() { initComponents(); @@ -69,6 +73,12 @@ public class ExtrasPanel label2 = new JLabel(); svgIconsPanel = new JPanel(); label3 = new JLabel(); + separator1 = new JSeparator(); + label5 = new JLabel(); + label6 = new JLabel(); + label7 = new JLabel(); + rainbowIcon = new JLabel(); + toggleButton1 = new JToggleButton(); //======== this ======== setLayout(new MigLayout( @@ -81,6 +91,9 @@ public class ExtrasPanel "[]para" + "[]" + "[]" + + "[]" + + "[]" + + "[]" + "[]")); //---- label4 ---- @@ -119,9 +132,55 @@ public class ExtrasPanel //---- label3 ---- label3.setText("The icons may change colors when switching to another theme."); add(label3, "cell 1 3 2 1"); + + add(separator1, "cell 1 4, grow"); + + //---- label5 ---- + label5.setText("Color filters can be also applied to icons. Globally or for each instance."); + add(label5, "cell 1 5"); + + //---- label6 ---- + label6.setText( "Rainbow color filter" ); + add(label6, "cell 1 6"); + + //---- rainbowIcon ---- + rainbowIcon = createRainbowIcon("informationDialog.svg"); + add(rainbowIcon, "cell 1 6"); + + //---- label7 ---- + label7.setText( "Global icon color filter" ); + add(label7, "cell 1 7"); + + // ---- button1 ---- + toggleButton1.setText( "Toggle red" ); + add(toggleButton1, "cell 1 7"); + + // ---- toggleButton1 ---- + toggleButton1.addActionListener( (e) -> { + if (toggleButton1.isSelected()) + FlatSVGIcon.ColorFilter.getInstance().setFilter( color -> Color.RED ); + else + FlatSVGIcon.ColorFilter.getInstance().setFilter( null ); + SwingUtilities.getRootPane( toggleButton1 ).repaint(); + } ); + // JFormDesigner - End of component initialization //GEN-END:initComponents } + private JLabel createRainbowIcon(String name) { + FlatSVGIcon rainbowIcon = new FlatSVGIcon( "com/formdev/flatlaf/demo/extras/svg/" + name); + rainbowIcon.setFilter( new ColorFilter( (color) -> { + counter+=1; + counter%=255; + return Color.getHSBColor(counter/255f, 1, 1); + }) ); + JLabel label = new JLabel(rainbowIcon); + new Timer(30, (e) -> { + label.repaint(); + }).start(); + return label; + } + // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables private JLabel label4; private JLabel label1; @@ -130,5 +189,11 @@ public class ExtrasPanel private JLabel label2; private JPanel svgIconsPanel; private JLabel label3; + private JLabel label5; + private JLabel label6; + private JLabel label7; + private JSeparator separator1; + private JLabel rainbowIcon; + private JToggleButton toggleButton1; // JFormDesigner - End of variables declaration //GEN-END:variables } diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatRGBFilter.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatRGBFilter.java deleted file mode 100644 index 83c1917c..00000000 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatRGBFilter.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.formdev.flatlaf.extras; - -import java.awt.*; -import java.awt.image.RGBImageFilter; - -/** - * A simplified RGBImageFilter that presents individual rgba components as a Color object. - * Can be used to modify the color of a {@link FlatSVGIcon}- - */ -public abstract class FlatRGBFilter extends RGBImageFilter -{ - @Override - public int filterRGB(int x, int y, int rgb) { - return filterRGB(new Color(rgb)).getRGB(); - } - - /** - * @param c Original color - * @return Modified color - */ - public abstract Color filterRGB(Color c); -} - diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index 2951c8a3..fd0c01ef 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -66,7 +66,7 @@ public class FlatSVGIcon private final boolean disabled; private final ClassLoader classLoader; - private RGBImageFilter userFilter = null; + private ColorFilter userColorFilter = null; private SVGDiagram diagram; private boolean dark; @@ -161,7 +161,7 @@ public class FlatSVGIcon this( name, -1, -1, scale, false, classLoader ); } - private FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader ) { + protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader ) { this.name = name; this.classLoader = classLoader; this.width = width; @@ -171,16 +171,29 @@ public class FlatSVGIcon } /** - * Sets an RGBImageFilter to be used when painting the icon. - * For simple RGB modifications you can use the {@link FlatRGBFilter}. - * @param filter + * Sets a color filter that can freely modify colors of this icon during painting.
+ *
+ * This method accepts a {@link ColorFilter}. Usually you would want to use a ColorFilter created using the + * {@link ColorFilter#ColorFilter(Function)} constructor.
+ *
+ * This can be used to brighten colors of the icon: + *
icon.setFilter( new FlatSVGIcon.ColorFilter( color -> color.brighter() ) );

+ *
+ * Using a filter, icons can also be turned monochrome (painted with a single color): + *
icon.setFilter( new FlatSVGIcon.ColorFilter( color -> Color.RED ) );

+ *
+ * Note: If a filter is already set, it will be replaced. + * @param filter The color filter */ - public void setFilter(RGBImageFilter filter) { - this.userFilter = filter; + public void setFilter(ColorFilter filter) { + this.userColorFilter = filter; } - public RGBImageFilter getFilter() { - return userFilter; + /** + * @return The currently active {@link ColorFilter} or null. + */ + public ColorFilter getFilter() { + return userColorFilter; } /** @@ -318,7 +331,7 @@ public class FlatSVGIcon : GrayFilter.createDisabledIconFilter( dark ); } - Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), grayFilter, this.userFilter ); + Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), grayFilter, this.userColorFilter ); try { FlatUIUtils.setRenderingHints( g2 ); @@ -416,37 +429,139 @@ public class FlatSVGIcon //---- class ColorFilter -------------------------------------------------- + /** + * A color filter that can modify colors of a painted {@link FlatSVGIcon}.
+ *
+ * The ColorFilter modifes color in two ways.
+ * Either using a color map, where specific colors are mapped to different ones.
+ * And/or by modifying the colors directly, applying a modification to their rgba values.
+ *
+ * When filtering a color. Mappings are applied first, then an rgb color filter is applied.
+ *
+ * Global {@link FlatSVGIcon} ColorFilter can be retrieved using the {@link ColorFilter#getInstance()} methods. + * + * @see ColorFilter#ColorFilter(Function) + * @see ColorFilter#ColorFilter(boolean) + */ public static class ColorFilter { private static ColorFilter instance; + //Color maps private final Map rgb2keyMap = new HashMap<>(); private final Map color2colorMap = new HashMap<>(); + //Color modification + private Function colorFilter = null; + + /** + * Returns the global ColorFilter instance. If one doesn't exist, a new one is created. + */ public static ColorFilter getInstance() { + return(getInstance(true)); + } + + /** + * Returns the global ColorFilter instance. If one doesn't exist, a new one is created. + * @param createDefaultColorMaps If true, default FlatLaf color maps are created. + */ + public static ColorFilter getInstance(boolean createDefaultColorMaps) { if( instance == null ) instance = new ColorFilter(); return instance; } + /** + * Creates a color filter with default color mappings. + */ public ColorFilter() { - for( FlatIconColors c : FlatIconColors.values() ) - rgb2keyMap.put( c.rgb, c.key ); + this(true); } + /** + * Creates a color filter. Default color maps can be optionally created. + * @param createDefaultColorMaps If true, default FlatLaf color maps are created. + */ + public ColorFilter(boolean createDefaultColorMaps) { + if (createDefaultColorMaps) { + for( FlatIconColors c : FlatIconColors.values() ) + rgb2keyMap.put( c.rgb, c.key ); + } + } + + /** + * Creates a color modifying function that changes painted colors.
+ * The {@link Function} gets passed the original color and returns a modified one. + *
+ * Examples: + * A ColorFilter can be used to brighten colors of the icon: + *
new ColorFilter( color -> color.brighter() );
+ *
+ * Using a ColorFilter, icons can also be turned monochrome (painted with a single color): + *
new ColorFilter( color -> Color.RED );
+ *
+ * @param filter The color filter function + */ + public ColorFilter(Function filter) { + setFilter(filter); + } + + /** + * Sets a color modifying function that changes painted colors.
+ * The {@link Function} gets passed the original color and returns a modified one. + *
+ * Examples: + * A ColorFilter can be used to brighten colors of the icon: + *
filter.setFilter( color -> color.brighter() );
+ *
+ * Using a ColorFilter, icons can also be turned monochrome (painted with a single color): + *
filter.setFilter( color -> Color.RED );
+ *
+ * @param filter The color filter function + */ + public void setFilter(Function filter) { + this.colorFilter = filter; + } + + /** + * Adds a color mappings. + */ public void addAll( Map from2toMap ) { color2colorMap.putAll( from2toMap ); } + /** + * Adds a color mapping. + */ public void add( Color from, Color to ) { color2colorMap.put( from, to ); } + /** + * Removes a specific color mapping. + */ public void remove( Color from ) { color2colorMap.remove( from ); } + /** + * Removes all color mappings. + */ + public void removeAll() { + for ( Color from : color2colorMap.keySet()) { + color2colorMap.remove( from ); + } + } + public Color filter( Color color ) { + color = filterMappings( color ); + if (colorFilter != null) { + color = colorFilter.apply( color ); + } + return color; + }; + + protected Color filterMappings( Color color ) { Color newColor = color2colorMap.get( color ); if( newColor != null ) return newColor; @@ -462,7 +577,7 @@ public class FlatSVGIcon return (newColor.getAlpha() != color.getAlpha()) ? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) ) : newColor; - }; + } } //---- class GraphicsFilter ----------------------------------------------- @@ -472,9 +587,9 @@ public class FlatSVGIcon { private final ColorFilter colorFilter; private final RGBImageFilter grayFilter; - private final RGBImageFilter userFilter; + private final ColorFilter userFilter; - public GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, RGBImageFilter grayFilter, RGBImageFilter userFilter) { + public GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, RGBImageFilter grayFilter,ColorFilter userFilter) { super( delegate ); this.colorFilter = colorFilter; this.grayFilter = grayFilter; @@ -494,11 +609,8 @@ public class FlatSVGIcon } private Color filterColor( Color color ) { - if( userFilter != null ) { - int oldRGB = color.getRGB(); - int newRGB = userFilter.filterRGB( 0, 0, oldRGB ); - color = (newRGB != oldRGB) ? new Color( newRGB, true ) : color; - } + if( userFilter != null ) + color = userFilter.filter( color ); if( colorFilter != null ) color = colorFilter.filter( color ); if( grayFilter != null ) { From d3bf4433b714b6a62b3907eb9a83412944cf719c Mon Sep 17 00:00:00 2001 From: DUDSS Date: Fri, 9 Apr 2021 13:26:10 +0200 Subject: [PATCH 03/11] FlatSVGIcon: Removed unnecessary getInstance method. Changed the demo a little and added a utility method to ColorFilter to easily create a brightness/contrast/alpha filter. --- .../flatlaf/demo/extras/ExtrasPanel.java | 5 ++- .../formdev/flatlaf/extras/FlatSVGIcon.java | 38 +++++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java index 9614920a..84dec7e3 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java @@ -20,6 +20,7 @@ import javax.swing.*; import com.formdev.flatlaf.extras.*; import com.formdev.flatlaf.extras.FlatSVGIcon.ColorFilter; import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox; +import com.formdev.flatlaf.util.GrayFilter; import net.miginfocom.swing.*; import java.awt.*; @@ -152,13 +153,13 @@ public class ExtrasPanel add(label7, "cell 1 7"); // ---- button1 ---- - toggleButton1.setText( "Toggle red" ); + toggleButton1.setText( "Toggle brighter" ); add(toggleButton1, "cell 1 7"); // ---- toggleButton1 ---- toggleButton1.addActionListener( (e) -> { if (toggleButton1.isSelected()) - FlatSVGIcon.ColorFilter.getInstance().setFilter( color -> Color.RED ); + FlatSVGIcon.ColorFilter.getInstance().setFilter( color -> color.brighter().brighter() ); else FlatSVGIcon.ColorFilter.getInstance().setFilter( null ); SwingUtilities.getRootPane( toggleButton1 ).repaint(); diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index fd0c01ef..b5e97b4f 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -331,7 +331,7 @@ public class FlatSVGIcon : GrayFilter.createDisabledIconFilter( dark ); } - Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), grayFilter, this.userColorFilter ); + Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), this.userColorFilter, grayFilter ); try { FlatUIUtils.setRenderingHints( g2 ); @@ -438,7 +438,7 @@ public class FlatSVGIcon *
* When filtering a color. Mappings are applied first, then an rgb color filter is applied.
*
- * Global {@link FlatSVGIcon} ColorFilter can be retrieved using the {@link ColorFilter#getInstance()} methods. + * Global {@link FlatSVGIcon} ColorFilter can be retrieved using the {@link ColorFilter#getInstance()} method. * * @see ColorFilter#ColorFilter(Function) * @see ColorFilter#ColorFilter(boolean) @@ -455,17 +455,9 @@ public class FlatSVGIcon private Function colorFilter = null; /** - * Returns the global ColorFilter instance. If one doesn't exist, a new one is created. + * Returns the global ColorFilter instance. If one doesn't exist, a new one is created with default color maps. */ public static ColorFilter getInstance() { - return(getInstance(true)); - } - - /** - * Returns the global ColorFilter instance. If one doesn't exist, a new one is created. - * @param createDefaultColorMaps If true, default FlatLaf color maps are created. - */ - public static ColorFilter getInstance(boolean createDefaultColorMaps) { if( instance == null ) instance = new ColorFilter(); return instance; @@ -490,7 +482,7 @@ public class FlatSVGIcon } /** - * Creates a color modifying function that changes painted colors.
+ * Creates a color filter with a color modifying function that changes painted colors.
* The {@link Function} gets passed the original color and returns a modified one. *
* Examples: @@ -545,7 +537,7 @@ public class FlatSVGIcon } /** - * Removes all color mappings. + * Removes all current color mappings. */ public void removeAll() { for ( Color from : color2colorMap.keySet()) { @@ -578,6 +570,19 @@ public class FlatSVGIcon ? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) ) : newColor; } + + /** + * Creates a color modifying function that changes color brightness, contrast and alpha. + * Can be set to a {@link ColorFilter} using {@link ColorFilter#setFilter(Function)}. + * + * @param brightness in range [-100..100] where 0 has no effect + * @param contrast in range [-100..100] where 0 has no effect + * @param alpha in range [0..100] where 0 is transparent, 100 has no effect + * @see GrayFilter + */ + public static Function createGrayFilterFunction(int brightness, int contrast, int alpha) { + return color -> new Color(new GrayFilter().filterRGB( 0, 0, color.getRGB() )); + } } //---- class GraphicsFilter ----------------------------------------------- @@ -589,11 +594,12 @@ public class FlatSVGIcon private final RGBImageFilter grayFilter; private final ColorFilter userFilter; - public GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, RGBImageFilter grayFilter,ColorFilter userFilter) { + public GraphicsFilter( Graphics2D delegate, ColorFilter globalColorFilter, ColorFilter userColorFilter, + RGBImageFilter grayFilter ) { super( delegate ); - this.colorFilter = colorFilter; + this.colorFilter = globalColorFilter; this.grayFilter = grayFilter; - this.userFilter = userFilter; + this.userFilter = userColorFilter; } @Override From e9b2f17171b444b7d4d34e7740eac52227b3d70e Mon Sep 17 00:00:00 2001 From: DUDSS Date: Fri, 9 Apr 2021 13:41:08 +0200 Subject: [PATCH 04/11] FlatSVGIcon: Fixed an oversight --- .../src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index b5e97b4f..850ba5de 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -581,7 +581,7 @@ public class FlatSVGIcon * @see GrayFilter */ public static Function createGrayFilterFunction(int brightness, int contrast, int alpha) { - return color -> new Color(new GrayFilter().filterRGB( 0, 0, color.getRGB() )); + return color -> new Color(new GrayFilter(brightness, contrast, alpha).filterRGB( 0, 0, color.getRGB() )); } } From ba9c884a0cbbfd8d21574c3e9406a50fa238c63e Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 16 Apr 2021 21:33:23 +0200 Subject: [PATCH 05/11] FlatSVGIcon: - renamed FlatSVGIcon.setFilter(...) to setColorFilter() - renamed ColorFilter.setFilter(Function) to setMapper(Function) - replaced ColorFilter.createGrayFilterFunction(int,int,int) with universal createRGBImageFilterFunction(RGBImageFilter) - ColorFilter: use default color palette mapping only in global filter --- .../flatlaf/demo/extras/ExtrasPanel.java | 7 +- .../formdev/flatlaf/extras/FlatSVGIcon.java | 206 +++++++++--------- 2 files changed, 110 insertions(+), 103 deletions(-) diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java index 84dec7e3..e3501e7c 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java @@ -20,7 +20,6 @@ import javax.swing.*; import com.formdev.flatlaf.extras.*; import com.formdev.flatlaf.extras.FlatSVGIcon.ColorFilter; import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox; -import com.formdev.flatlaf.util.GrayFilter; import net.miginfocom.swing.*; import java.awt.*; @@ -159,9 +158,9 @@ public class ExtrasPanel // ---- toggleButton1 ---- toggleButton1.addActionListener( (e) -> { if (toggleButton1.isSelected()) - FlatSVGIcon.ColorFilter.getInstance().setFilter( color -> color.brighter().brighter() ); + FlatSVGIcon.ColorFilter.getInstance().setMapper( color -> color.brighter() ); else - FlatSVGIcon.ColorFilter.getInstance().setFilter( null ); + FlatSVGIcon.ColorFilter.getInstance().setMapper( null ); SwingUtilities.getRootPane( toggleButton1 ).repaint(); } ); @@ -170,7 +169,7 @@ public class ExtrasPanel private JLabel createRainbowIcon(String name) { FlatSVGIcon rainbowIcon = new FlatSVGIcon( "com/formdev/flatlaf/demo/extras/svg/" + name); - rainbowIcon.setFilter( new ColorFilter( (color) -> { + rainbowIcon.setColorFilter( new ColorFilter( (color) -> { counter+=1; counter%=255; return Color.getHSBColor(counter/255f, 1, 1); diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index 850ba5de..3cfb418f 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -66,7 +66,7 @@ public class FlatSVGIcon private final boolean disabled; private final ClassLoader classLoader; - private ColorFilter userColorFilter = null; + private ColorFilter colorFilter; private SVGDiagram diagram; private boolean dark; @@ -163,37 +163,11 @@ public class FlatSVGIcon protected FlatSVGIcon( String name, int width, int height, float scale, boolean disabled, ClassLoader classLoader ) { this.name = name; - this.classLoader = classLoader; this.width = width; this.height = height; this.scale = scale; this.disabled = disabled; - } - - /** - * Sets a color filter that can freely modify colors of this icon during painting.
- *
- * This method accepts a {@link ColorFilter}. Usually you would want to use a ColorFilter created using the - * {@link ColorFilter#ColorFilter(Function)} constructor.
- *
- * This can be used to brighten colors of the icon: - *
icon.setFilter( new FlatSVGIcon.ColorFilter( color -> color.brighter() ) );

- *
- * Using a filter, icons can also be turned monochrome (painted with a single color): - *
icon.setFilter( new FlatSVGIcon.ColorFilter( color -> Color.RED ) );

- *
- * Note: If a filter is already set, it will be replaced. - * @param filter The color filter - */ - public void setFilter(ColorFilter filter) { - this.userColorFilter = filter; - } - - /** - * @return The currently active {@link ColorFilter} or null. - */ - public ColorFilter getFilter() { - return userColorFilter; + this.classLoader = classLoader; } /** @@ -245,6 +219,36 @@ public class FlatSVGIcon return icon; } + /** + * Returns the currently active color filter or {@code null}. + * + * @since 1.2 + */ + public ColorFilter getColorFilter() { + return colorFilter; + } + + /** + * Sets a color filter that can freely modify colors of this icon during painting. + *

+ * This method accepts a {@link ColorFilter}. Usually you would want to use a ColorFilter created using the + * {@link ColorFilter#ColorFilter(Function)} constructor. + *

+ * This can be used to brighten colors of the icon: + *

icon.setColorFilter( new FlatSVGIcon.ColorFilter( color -> color.brighter() ) );
+ *

+ * Using a filter, icons can also be turned monochrome (painted with a single color): + *

icon.setColorFilter( new FlatSVGIcon.ColorFilter( color -> Color.RED ) );
+ *

+ * Note: If a filter is already set, it will be replaced. + * + * @param colorFilter The color filter + * @since 1.2 + */ + public void setColorFilter( ColorFilter colorFilter ) { + this.colorFilter = colorFilter; + } + private void update() { if( dark == isDarkLaf() && diagram != null ) return; @@ -331,7 +335,7 @@ public class FlatSVGIcon : GrayFilter.createDisabledIconFilter( dark ); } - Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), this.userColorFilter, grayFilter ); + Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), colorFilter, ColorFilter.getInstance(), grayFilter ); try { FlatUIUtils.setRenderingHints( g2 ); @@ -430,93 +434,91 @@ public class FlatSVGIcon //---- class ColorFilter -------------------------------------------------- /** - * A color filter that can modify colors of a painted {@link FlatSVGIcon}.
- *
- * The ColorFilter modifes color in two ways.
- * Either using a color map, where specific colors are mapped to different ones.
- * And/or by modifying the colors directly, applying a modification to their rgba values.
- *
- * When filtering a color. Mappings are applied first, then an rgb color filter is applied.
- *
+ * A color filter that can modify colors of a painted {@link FlatSVGIcon}. + *

+ * The ColorFilter modifies color in two ways. + * Either using a color map, where specific colors are mapped to different ones. + * And/or by modifying the colors in a mapper function. + *

+ * When filtering a color, mappings are applied first, then the mapper function is applied. + *

* Global {@link FlatSVGIcon} ColorFilter can be retrieved using the {@link ColorFilter#getInstance()} method. - * - * @see ColorFilter#ColorFilter(Function) - * @see ColorFilter#ColorFilter(boolean) */ public static class ColorFilter { private static ColorFilter instance; - //Color maps private final Map rgb2keyMap = new HashMap<>(); private final Map color2colorMap = new HashMap<>(); - - //Color modification - private Function colorFilter = null; + private Function mapper; /** - * Returns the global ColorFilter instance. If one doesn't exist, a new one is created with default color maps. + * Returns the global ColorFilter that is applied to all icons. */ public static ColorFilter getInstance() { - if( instance == null ) + if( instance == null ) { instance = new ColorFilter(); + + // add default color palette + for( FlatIconColors c : FlatIconColors.values() ) + instance.rgb2keyMap.put( c.rgb, c.key ); + } return instance; } /** - * Creates a color filter with default color mappings. + * Creates an empty color filter. */ public ColorFilter() { - this(true); } /** - * Creates a color filter. Default color maps can be optionally created. - * @param createDefaultColorMaps If true, default FlatLaf color maps are created. - */ - public ColorFilter(boolean createDefaultColorMaps) { - if (createDefaultColorMaps) { - for( FlatIconColors c : FlatIconColors.values() ) - rgb2keyMap.put( c.rgb, c.key ); - } - } - - /** - * Creates a color filter with a color modifying function that changes painted colors.
+ * Creates a color filter with a color modifying function that changes painted colors. * The {@link Function} gets passed the original color and returns a modified one. - *
+ *

* Examples: * A ColorFilter can be used to brighten colors of the icon: *

new ColorFilter( color -> color.brighter() );
- *
+ *

* Using a ColorFilter, icons can also be turned monochrome (painted with a single color): *

new ColorFilter( color -> Color.RED );
- *
- * @param filter The color filter function + * + * @param mapper The color mapper function + * @since 1.2 */ - public ColorFilter(Function filter) { - setFilter(filter); + public ColorFilter( Function mapper ) { + setMapper( mapper ); } /** - * Sets a color modifying function that changes painted colors.
+ * Returns a color modifying function or {@code null} + * + * @since 1.2 + */ + public Function getMapper() { + return mapper; + } + + /** + * Sets a color modifying function that changes painted colors. * The {@link Function} gets passed the original color and returns a modified one. - *
+ *

* Examples: * A ColorFilter can be used to brighten colors of the icon: - *

filter.setFilter( color -> color.brighter() );
- *
+ *
filter.setMapper( color -> color.brighter() );
+ *

* Using a ColorFilter, icons can also be turned monochrome (painted with a single color): - *

filter.setFilter( color -> Color.RED );
- *
- * @param filter The color filter function + *
filter.setMapper( color -> Color.RED );
+ * + * @param mapper The color mapper function + * @since 1.2 */ - public void setFilter(Function filter) { - this.colorFilter = filter; + public void setMapper( Function mapper ) { + this.mapper = mapper; } /** - * Adds a color mappings. + * Adds color mappings. */ public void addAll( Map from2toMap ) { color2colorMap.putAll( from2toMap ); @@ -537,23 +539,26 @@ public class FlatSVGIcon } /** - * Removes all current color mappings. + * Removes all color mappings. + * + * @since 1.2 */ public void removeAll() { - for ( Color from : color2colorMap.keySet()) { - color2colorMap.remove( from ); - } + color2colorMap.clear(); } public Color filter( Color color ) { - color = filterMappings( color ); - if (colorFilter != null) { - color = colorFilter.apply( color ); - } + // apply mappings + color = applyMappings( color ); + + // apply mapper function + if( mapper != null ) + color = mapper.apply( color ); + return color; }; - protected Color filterMappings( Color color ) { + private Color applyMappings( Color color ) { Color newColor = color2colorMap.get( color ); if( newColor != null ) return newColor; @@ -572,16 +577,18 @@ public class FlatSVGIcon } /** - * Creates a color modifying function that changes color brightness, contrast and alpha. - * Can be set to a {@link ColorFilter} using {@link ColorFilter#setFilter(Function)}. + * Creates a color modifying function that uses {@link RGBImageFilter#filterRGB(int, int, int)}. + * Can be set to a {@link ColorFilter} using {@link ColorFilter#setMapper(Function)}. * - * @param brightness in range [-100..100] where 0 has no effect - * @param contrast in range [-100..100] where 0 has no effect - * @param alpha in range [0..100] where 0 is transparent, 100 has no effect * @see GrayFilter + * @since 1.2 */ - public static Function createGrayFilterFunction(int brightness, int contrast, int alpha) { - return color -> new Color(new GrayFilter(brightness, contrast, alpha).filterRGB( 0, 0, color.getRGB() )); + public static Function createRGBImageFilterFunction( RGBImageFilter rgbImageFilter ) { + return color -> { + int oldRGB = color.getRGB(); + int newRGB = rgbImageFilter.filterRGB( 0, 0, oldRGB ); + return (newRGB != oldRGB) ? new Color( newRGB, true ) : color; + }; } } @@ -591,15 +598,16 @@ public class FlatSVGIcon extends Graphics2DProxy { private final ColorFilter colorFilter; + private final ColorFilter globalColorFilter; private final RGBImageFilter grayFilter; - private final ColorFilter userFilter; - public GraphicsFilter( Graphics2D delegate, ColorFilter globalColorFilter, ColorFilter userColorFilter, - RGBImageFilter grayFilter ) { + GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, + ColorFilter globalColorFilter, RGBImageFilter grayFilter ) + { super( delegate ); - this.colorFilter = globalColorFilter; + this.colorFilter = colorFilter; + this.globalColorFilter = globalColorFilter; this.grayFilter = grayFilter; - this.userFilter = userColorFilter; } @Override @@ -615,10 +623,10 @@ public class FlatSVGIcon } private Color filterColor( Color color ) { - if( userFilter != null ) - color = userFilter.filter( color ); if( colorFilter != null ) color = colorFilter.filter( color ); + if( globalColorFilter != null ) + color = globalColorFilter.filter( color ); if( grayFilter != null ) { int oldRGB = color.getRGB(); int newRGB = grayFilter.filterRGB( 0, 0, oldRGB ); From 6c48489d895455db68b190badf278004839ddf60 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 16 Apr 2021 21:53:15 +0200 Subject: [PATCH 06/11] FlatSVGIcon: - added getters for all fields passed to constructors - preserve disabled state in derive() methods - ColorFilter: create hash maps only if needed/used --- .../formdev/flatlaf/extras/FlatSVGIcon.java | 115 +++++++++++++++--- 1 file changed, 97 insertions(+), 18 deletions(-) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index 3cfb418f..9b17d130 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -170,6 +170,69 @@ public class FlatSVGIcon this.classLoader = classLoader; } + /** + * Returns the name of the SVG resource (a '/'-separated path). + * + * @since 1.2 + */ + public String getName() { + return name; + } + + /** + * Returns the custom icon width specified in {@link #FlatSVGIcon(String, int, int)}, + * {@link #FlatSVGIcon(String, int, int, ClassLoader)} or {@link #derive(int, int)}. + * Otherwise {@code -1} is returned. + *

+ * To get the painted icon width, use {@link #getIconWidth()}. + * + * @since 1.2 + */ + public int getWidth() { + return width; + } + + /** + * Returns the custom icon height specified in {@link #FlatSVGIcon(String, int, int)}, + * {@link #FlatSVGIcon(String, int, int, ClassLoader)} or {@link #derive(int, int)}. + * Otherwise {@code -1} is returned. + *

+ * To get the painted icon height, use {@link #getIconHeight()}. + * + * @since 1.2 + */ + public int getHeight() { + return height; + } + + /** + * Returns the amount by which the icon size is scaled. Usually {@code 1}. + * + * @since 1.2 + */ + public float getScale() { + return scale; + } + + /** + * Returns whether the icon is pained in "disabled" state. + * + * @see #getDisabledIcon() + * @since 1.2 + */ + public boolean isDisabled() { + return disabled; + } + + /** + * Returns the class loader used to load the SVG resource. + * + * @since 1.2 + */ + public ClassLoader getClassLoader() { + return classLoader; + } + /** * Creates a new icon with given width and height, which is derived from this icon. * @@ -181,7 +244,7 @@ public class FlatSVGIcon if( width == this.width && height == this.height ) return this; - FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, false, classLoader ); + FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader ); icon.diagram = diagram; icon.dark = dark; return icon; @@ -197,7 +260,7 @@ public class FlatSVGIcon if( scale == this.scale ) return this; - FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, false, classLoader ); + FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, disabled, classLoader ); icon.diagram = diagram; icon.dark = dark; return icon; @@ -448,8 +511,8 @@ public class FlatSVGIcon { private static ColorFilter instance; - private final Map rgb2keyMap = new HashMap<>(); - private final Map color2colorMap = new HashMap<>(); + private Map rgb2keyMap; + private Map color2colorMap; private Function mapper; /** @@ -460,6 +523,7 @@ public class FlatSVGIcon instance = new ColorFilter(); // add default color palette + instance.rgb2keyMap = new HashMap<>(); for( FlatIconColors c : FlatIconColors.values() ) instance.rgb2keyMap.put( c.rgb, c.key ); } @@ -521,6 +585,8 @@ public class FlatSVGIcon * Adds color mappings. */ public void addAll( Map from2toMap ) { + if( color2colorMap == null ) + color2colorMap = new HashMap<>(); color2colorMap.putAll( from2toMap ); } @@ -528,6 +594,8 @@ public class FlatSVGIcon * Adds a color mapping. */ public void add( Color from, Color to ) { + if( color2colorMap == null ) + color2colorMap = new HashMap<>(); color2colorMap.put( from, to ); } @@ -535,7 +603,8 @@ public class FlatSVGIcon * Removes a specific color mapping. */ public void remove( Color from ) { - color2colorMap.remove( from ); + if( color2colorMap != null ) + color2colorMap.remove( from ); } /** @@ -544,7 +613,8 @@ public class FlatSVGIcon * @since 1.2 */ public void removeAll() { - color2colorMap.clear(); + if( color2colorMap != null ) + color2colorMap.clear(); } public Color filter( Color color ) { @@ -559,21 +629,30 @@ public class FlatSVGIcon }; private Color applyMappings( Color color ) { - Color newColor = color2colorMap.get( color ); - if( newColor != null ) - return newColor; + if( color2colorMap != null ) { + Color newColor = color2colorMap.get( color ); + if( newColor != null ) + return newColor; + } - String colorKey = rgb2keyMap.get( color.getRGB() & 0xffffff ); - if( colorKey == null ) - return color; + if( rgb2keyMap != null ) { + // RGB is mapped to a key in UI defaults, which contains the real color. + // IntelliJ themes define such theme specific icon colors in .theme.json files. + String colorKey = rgb2keyMap.get( color.getRGB() & 0xffffff ); + if( colorKey == null ) + return color; - newColor = UIManager.getColor( colorKey ); - if( newColor == null ) - return color; + Color newColor = UIManager.getColor( colorKey ); + if( newColor == null ) + return color; - return (newColor.getAlpha() != color.getAlpha()) - ? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) ) - : newColor; + // preserve alpha of original color + return (newColor.getAlpha() != color.getAlpha()) + ? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) ) + : newColor; + } + + return color; } /** From 584fa0a26e5ccede2bd3aad33cf47767e82c5233 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 16 Apr 2021 22:31:31 +0200 Subject: [PATCH 07/11] Demo: ExtrasPanel: - animate "rainbow" icon only if extras tab is visible - recreated added components in JFormDesigner --- .../flatlaf/demo/extras/ExtrasPanel.java | 102 ++++++++++-------- .../flatlaf/demo/extras/ExtrasPanel.jfd | 39 ++++++- 2 files changed, 95 insertions(+), 46 deletions(-) diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java index e3501e7c..87abda55 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java @@ -22,6 +22,7 @@ import com.formdev.flatlaf.extras.FlatSVGIcon.ColorFilter; import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox; import net.miginfocom.swing.*; import java.awt.*; +import java.awt.event.HierarchyEvent; /** * @author Karl Tauber @@ -29,7 +30,8 @@ import java.awt.*; public class ExtrasPanel extends JPanel { - public int counter = 0; + private Timer rainbowIconTimer; + private int rainbowCounter = 0; public ExtrasPanel() { initComponents(); @@ -54,6 +56,34 @@ public class ExtrasPanel addSVGIcon( "errorDialog.svg" ); addSVGIcon( "informationDialog.svg" ); addSVGIcon( "warningDialog.svg" ); + + initRainbowIcon(); + } + + private void initRainbowIcon() { + FlatSVGIcon icon = new FlatSVGIcon( "com/formdev/flatlaf/demo/extras/svg/informationDialog.svg" ); + icon.setColorFilter( new ColorFilter( color -> { + rainbowCounter += 1; + rainbowCounter %= 255; + return Color.getHSBColor( rainbowCounter / 255f, 1, 1 ); + } ) ); + rainbowIcon.setIcon( icon ); + + rainbowIconTimer = new Timer( 30, e -> { + rainbowIcon.repaint(); + } ); + + // start rainbow timer only if panel is shown ("Extras" tab is active) + addHierarchyListener( e -> { + if( e.getID() == HierarchyEvent.HIERARCHY_CHANGED && + (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 ) + { + if( isShowing() ) + rainbowIconTimer.start(); + else + rainbowIconTimer.stop(); + } + } ); } private void addSVGIcon( String name ) { @@ -64,6 +94,16 @@ public class ExtrasPanel triStateLabel1.setText( triStateCheckBox1.getState().toString() ); } + private void brighterChanged() { + FlatSVGIcon.ColorFilter.getInstance().setMapper( brighterToggleButton.isSelected() + ? color -> color.brighter().brighter() + : null ); + + // repaint whole application window because global color filter also affects + // icons in menubar, toolbar, etc. + SwingUtilities.windowForComponent( this ).repaint(); + } + private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents label4 = new JLabel(); @@ -76,9 +116,9 @@ public class ExtrasPanel separator1 = new JSeparator(); label5 = new JLabel(); label6 = new JLabel(); - label7 = new JLabel(); rainbowIcon = new JLabel(); - toggleButton1 = new JToggleButton(); + label7 = new JLabel(); + brighterToggleButton = new JToggleButton(); //======== this ======== setLayout(new MigLayout( @@ -94,6 +134,7 @@ public class ExtrasPanel "[]" + "[]" + "[]" + + "[]" + "[]")); //---- label4 ---- @@ -132,55 +173,28 @@ public class ExtrasPanel //---- label3 ---- label3.setText("The icons may change colors when switching to another theme."); add(label3, "cell 1 3 2 1"); - - add(separator1, "cell 1 4, grow"); + add(separator1, "cell 1 4 2 1,growx"); //---- label5 ---- label5.setText("Color filters can be also applied to icons. Globally or for each instance."); - add(label5, "cell 1 5"); + add(label5, "cell 1 5 2 1"); //---- label6 ---- - label6.setText( "Rainbow color filter" ); - add(label6, "cell 1 6"); - - //---- rainbowIcon ---- - rainbowIcon = createRainbowIcon("informationDialog.svg"); - add(rainbowIcon, "cell 1 6"); + label6.setText("Rainbow color filter"); + add(label6, "cell 1 6 2 1"); + add(rainbowIcon, "cell 1 6 2 1"); //---- label7 ---- - label7.setText( "Global icon color filter" ); - add(label7, "cell 1 7"); - - // ---- button1 ---- - toggleButton1.setText( "Toggle brighter" ); - add(toggleButton1, "cell 1 7"); - - // ---- toggleButton1 ---- - toggleButton1.addActionListener( (e) -> { - if (toggleButton1.isSelected()) - FlatSVGIcon.ColorFilter.getInstance().setMapper( color -> color.brighter() ); - else - FlatSVGIcon.ColorFilter.getInstance().setMapper( null ); - SwingUtilities.getRootPane( toggleButton1 ).repaint(); - } ); + label7.setText("Global icon color filter"); + add(label7, "cell 1 7 2 1"); + //---- brighterToggleButton ---- + brighterToggleButton.setText("Toggle brighter"); + brighterToggleButton.addActionListener(e -> brighterChanged()); + add(brighterToggleButton, "cell 1 7 2 1"); // JFormDesigner - End of component initialization //GEN-END:initComponents } - private JLabel createRainbowIcon(String name) { - FlatSVGIcon rainbowIcon = new FlatSVGIcon( "com/formdev/flatlaf/demo/extras/svg/" + name); - rainbowIcon.setColorFilter( new ColorFilter( (color) -> { - counter+=1; - counter%=255; - return Color.getHSBColor(counter/255f, 1, 1); - }) ); - JLabel label = new JLabel(rainbowIcon); - new Timer(30, (e) -> { - label.repaint(); - }).start(); - return label; - } - // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables private JLabel label4; private JLabel label1; @@ -189,11 +203,11 @@ public class ExtrasPanel private JLabel label2; private JPanel svgIconsPanel; private JLabel label3; + private JSeparator separator1; private JLabel label5; private JLabel label6; - private JLabel label7; - private JSeparator separator1; private JLabel rainbowIcon; - private JToggleButton toggleButton1; + private JLabel label7; + private JToggleButton brighterToggleButton; // JFormDesigner - End of variables declaration //GEN-END:variables } diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.jfd index a121bc65..8d51c8c1 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.jfd +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.jfd @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.3.1.342" Java: "16" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -6,7 +6,7 @@ new FormModel { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets dialog,hidemode 3" "$columnConstraints": "[][][left]" - "$rowConstraints": "[]para[][][]" + "$rowConstraints": "[]para[][][][][][][]" } ) { name: "this" add( new FormComponent( "javax.swing.JLabel" ) { @@ -56,6 +56,41 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 3 2 1" } ) + add( new FormComponent( "javax.swing.JSeparator" ) { + name: "separator1" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4 2 1,growx" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "label5" + "text": "Color filters can be also applied to icons. Globally or for each instance." + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 5 2 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "label6" + "text": "Rainbow color filter" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 6 2 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "rainbowIcon" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 6 2 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "label7" + "text": "Global icon color filter" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 7 2 1" + } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "brighterToggleButton" + "text": "Toggle brighter" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "brighterChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 7 2 1" + } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) "size": new java.awt.Dimension( 500, 300 ) From 34861166e8f14f19c90b9e5c5f4e70d8e9be98a5 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 16 Apr 2021 23:03:38 +0200 Subject: [PATCH 08/11] Demo: ExtrasPanel: added "Toggle RED" button --- .../flatlaf/demo/extras/ExtrasPanel.java | 29 +++++++++++++++++++ .../flatlaf/demo/extras/ExtrasPanel.jfd | 7 +++++ 2 files changed, 36 insertions(+) diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java index 87abda55..34d79a7d 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.java @@ -20,9 +20,11 @@ import javax.swing.*; import com.formdev.flatlaf.extras.*; import com.formdev.flatlaf.extras.FlatSVGIcon.ColorFilter; import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox; +import com.formdev.flatlaf.util.HSLColor; import net.miginfocom.swing.*; import java.awt.*; import java.awt.event.HierarchyEvent; +import java.util.function.Function; /** * @author Karl Tauber @@ -94,7 +96,27 @@ public class ExtrasPanel triStateLabel1.setText( triStateCheckBox1.getState().toString() ); } + private void redChanged() { + brighterToggleButton.setSelected( false ); + + Function mapper = null; + if( redToggleButton.isSelected() ) { + float[] redHSL = HSLColor.fromRGB( Color.red ); + mapper = color -> { + float[] hsl = HSLColor.fromRGB( color ); + return HSLColor.toRGB( redHSL[0], 70, hsl[2] ); + }; + } + FlatSVGIcon.ColorFilter.getInstance().setMapper( mapper ); + + // repaint whole application window because global color filter also affects + // icons in menubar, toolbar, etc. + SwingUtilities.windowForComponent( this ).repaint(); + } + private void brighterChanged() { + redToggleButton.setSelected( false ); + FlatSVGIcon.ColorFilter.getInstance().setMapper( brighterToggleButton.isSelected() ? color -> color.brighter().brighter() : null ); @@ -118,6 +140,7 @@ public class ExtrasPanel label6 = new JLabel(); rainbowIcon = new JLabel(); label7 = new JLabel(); + redToggleButton = new JToggleButton(); brighterToggleButton = new JToggleButton(); //======== this ======== @@ -188,6 +211,11 @@ public class ExtrasPanel label7.setText("Global icon color filter"); add(label7, "cell 1 7 2 1"); + //---- redToggleButton ---- + redToggleButton.setText("Toggle RED"); + redToggleButton.addActionListener(e -> redChanged()); + add(redToggleButton, "cell 1 7 2 1"); + //---- brighterToggleButton ---- brighterToggleButton.setText("Toggle brighter"); brighterToggleButton.addActionListener(e -> brighterChanged()); @@ -208,6 +236,7 @@ public class ExtrasPanel private JLabel label6; private JLabel rainbowIcon; private JLabel label7; + private JToggleButton redToggleButton; private JToggleButton brighterToggleButton; // JFormDesigner - End of variables declaration //GEN-END:variables } diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.jfd index 8d51c8c1..8fe606f3 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.jfd +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/extras/ExtrasPanel.jfd @@ -84,6 +84,13 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 7 2 1" } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "redToggleButton" + "text": "Toggle RED" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "redChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 7 2 1" + } ) add( new FormComponent( "javax.swing.JToggleButton" ) { name: "brighterToggleButton" "text": "Toggle brighter" From ec2fccbb0e53ab5d1535d79568721885b9e50be2 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 16 Apr 2021 23:25:22 +0200 Subject: [PATCH 09/11] FlatSVGIcon: if icon has color filter and did change the color, then do not apply global color filter --- .../java/com/formdev/flatlaf/extras/FlatSVGIcon.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index 9b17d130..e6d1559c 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -702,10 +702,14 @@ public class FlatSVGIcon } private Color filterColor( Color color ) { - if( colorFilter != null ) - color = colorFilter.filter( color ); - if( globalColorFilter != null ) + if( colorFilter != null ) { + Color newColor = colorFilter.filter( color ); + color = (newColor != color) + ? newColor + : globalColorFilter.filter( color ); + } else color = globalColorFilter.filter( color ); + if( grayFilter != null ) { int oldRGB = color.getRGB(); int newRGB = grayFilter.filterRGB( 0, 0, oldRGB ); From d75dc9e70c359e4f99b0fca13dc31479af3aff5a Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 18 Apr 2021 16:37:24 +0200 Subject: [PATCH 10/11] FlatSVGIcon: support light and dark mappings in single color filter --- .../formdev/flatlaf/extras/FlatSVGIcon.java | 103 +++++++++++++++--- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index e6d1559c..5899ea9e 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -29,6 +29,7 @@ import java.awt.image.BufferedImage; import java.awt.image.RGBImageFilter; import java.net.URISyntaxException; import java.net.URL; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @@ -478,7 +479,7 @@ public class FlatSVGIcon private static Boolean darkLaf; - private static boolean isDarkLaf() { + public static boolean isDarkLaf() { if( darkLaf == null ) { lafChanged(); @@ -512,7 +513,8 @@ public class FlatSVGIcon private static ColorFilter instance; private Map rgb2keyMap; - private Map color2colorMap; + private Map colorMap; + private Map darkColorMap; private Function mapper; /** @@ -582,29 +584,85 @@ public class FlatSVGIcon } /** - * Adds color mappings. + * Returns the color mappings used for light themes. + * + * @since 1.2 */ - public void addAll( Map from2toMap ) { - if( color2colorMap == null ) - color2colorMap = new HashMap<>(); - color2colorMap.putAll( from2toMap ); + public Map getLightColorMap() { + return (colorMap != null) + ? Collections.unmodifiableMap( colorMap ) + : Collections.emptyMap(); } /** - * Adds a color mapping. + * Returns the color mappings used for dark themes. + * + * @since 1.2 + */ + public Map getDarkColorMap() { + return (darkColorMap != null) + ? Collections.unmodifiableMap( darkColorMap ) + : getLightColorMap(); + } + + /** + * Adds color mappings. Used for light and dark themes. + */ + public void addAll( Map from2toMap ) { + ensureColorMap(); + + colorMap.putAll( from2toMap ); + if( darkColorMap != null ) + darkColorMap.putAll( from2toMap ); + } + + /** + * Adds a color mappings, which has different colors for light and dark themes. + * + * @since 1.2 + */ + public void addAll( Map from2toLightMap, Map from2toDarkMap ) { + ensureColorMap(); + ensureDarkColorMap(); + + colorMap.putAll( from2toLightMap ); + darkColorMap.putAll( from2toDarkMap ); + } + + /** + * Adds a color mapping. Used for light and dark themes. */ public void add( Color from, Color to ) { - if( color2colorMap == null ) - color2colorMap = new HashMap<>(); - color2colorMap.put( from, to ); + ensureColorMap(); + + colorMap.put( from, to ); + if( darkColorMap != null ) + darkColorMap.put( from, to ); + } + + /** + * Adds a color mapping, which has different colors for light and dark themes. + * + * @since 1.2 + */ + public void add( Color from, Color toLight, Color toDark ) { + ensureColorMap(); + ensureDarkColorMap(); + + if( toLight != null ) + colorMap.put( from, toLight ); + if( toDark != null ) + darkColorMap.put( from, toDark ); } /** * Removes a specific color mapping. */ public void remove( Color from ) { - if( color2colorMap != null ) - color2colorMap.remove( from ); + if( colorMap != null ) + colorMap.remove( from ); + if( darkColorMap != null ) + darkColorMap.remove( from ); } /** @@ -613,8 +671,18 @@ public class FlatSVGIcon * @since 1.2 */ public void removeAll() { - if( color2colorMap != null ) - color2colorMap.clear(); + colorMap = null; + darkColorMap = null; + } + + private void ensureColorMap() { + if( colorMap == null ) + colorMap = new HashMap<>(); + } + + private void ensureDarkColorMap() { + if( darkColorMap == null ) + darkColorMap = new HashMap<>( colorMap ); } public Color filter( Color color ) { @@ -629,8 +697,9 @@ public class FlatSVGIcon }; private Color applyMappings( Color color ) { - if( color2colorMap != null ) { - Color newColor = color2colorMap.get( color ); + if( colorMap != null ) { + Map map = (darkColorMap != null && isDarkLaf()) ? darkColorMap : colorMap; + Color newColor = map.get( color ); if( newColor != null ) return newColor; } From 8ec0e57235518d57cc471757b27666b4153629e1 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 18 Apr 2021 17:05:22 +0200 Subject: [PATCH 11/11] FlatSVGIcon: use fluent API for color filter --- .../formdev/flatlaf/extras/FlatSVGIcon.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java index 5899ea9e..f97fa5a3 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java @@ -608,12 +608,13 @@ public class FlatSVGIcon /** * Adds color mappings. Used for light and dark themes. */ - public void addAll( Map from2toMap ) { + public ColorFilter addAll( Map from2toMap ) { ensureColorMap(); colorMap.putAll( from2toMap ); if( darkColorMap != null ) darkColorMap.putAll( from2toMap ); + return this; } /** @@ -621,23 +622,25 @@ public class FlatSVGIcon * * @since 1.2 */ - public void addAll( Map from2toLightMap, Map from2toDarkMap ) { + public ColorFilter addAll( Map from2toLightMap, Map from2toDarkMap ) { ensureColorMap(); ensureDarkColorMap(); colorMap.putAll( from2toLightMap ); darkColorMap.putAll( from2toDarkMap ); + return this; } /** * Adds a color mapping. Used for light and dark themes. */ - public void add( Color from, Color to ) { + public ColorFilter add( Color from, Color to ) { ensureColorMap(); colorMap.put( from, to ); if( darkColorMap != null ) darkColorMap.put( from, to ); + return this; } /** @@ -645,7 +648,7 @@ public class FlatSVGIcon * * @since 1.2 */ - public void add( Color from, Color toLight, Color toDark ) { + public ColorFilter add( Color from, Color toLight, Color toDark ) { ensureColorMap(); ensureDarkColorMap(); @@ -653,16 +656,18 @@ public class FlatSVGIcon colorMap.put( from, toLight ); if( toDark != null ) darkColorMap.put( from, toDark ); + return this; } /** * Removes a specific color mapping. */ - public void remove( Color from ) { + public ColorFilter remove( Color from ) { if( colorMap != null ) colorMap.remove( from ); if( darkColorMap != null ) darkColorMap.remove( from ); + return this; } /** @@ -670,9 +675,10 @@ public class FlatSVGIcon * * @since 1.2 */ - public void removeAll() { + public ColorFilter removeAll() { colorMap = null; darkColorMap = null; + return this; } private void ensureColorMap() {