mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-10 22:17:13 -06:00
Merge pull request #303 from xDUDSSx/extras-svg-icon-filter
FlatSVGIcon color filters
This commit is contained in:
@@ -18,8 +18,13 @@ package com.formdev.flatlaf.demo.extras;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import com.formdev.flatlaf.extras.*;
|
import com.formdev.flatlaf.extras.*;
|
||||||
|
import com.formdev.flatlaf.extras.FlatSVGIcon.ColorFilter;
|
||||||
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox;
|
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox;
|
||||||
|
import com.formdev.flatlaf.util.HSLColor;
|
||||||
import net.miginfocom.swing.*;
|
import net.miginfocom.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.HierarchyEvent;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
@@ -27,6 +32,9 @@ import net.miginfocom.swing.*;
|
|||||||
public class ExtrasPanel
|
public class ExtrasPanel
|
||||||
extends JPanel
|
extends JPanel
|
||||||
{
|
{
|
||||||
|
private Timer rainbowIconTimer;
|
||||||
|
private int rainbowCounter = 0;
|
||||||
|
|
||||||
public ExtrasPanel() {
|
public ExtrasPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
@@ -50,6 +58,34 @@ public class ExtrasPanel
|
|||||||
addSVGIcon( "errorDialog.svg" );
|
addSVGIcon( "errorDialog.svg" );
|
||||||
addSVGIcon( "informationDialog.svg" );
|
addSVGIcon( "informationDialog.svg" );
|
||||||
addSVGIcon( "warningDialog.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 ) {
|
private void addSVGIcon( String name ) {
|
||||||
@@ -60,6 +96,36 @@ public class ExtrasPanel
|
|||||||
triStateLabel1.setText( triStateCheckBox1.getState().toString() );
|
triStateLabel1.setText( triStateCheckBox1.getState().toString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void redChanged() {
|
||||||
|
brighterToggleButton.setSelected( false );
|
||||||
|
|
||||||
|
Function<Color, Color> 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 );
|
||||||
|
|
||||||
|
// repaint whole application window because global color filter also affects
|
||||||
|
// icons in menubar, toolbar, etc.
|
||||||
|
SwingUtilities.windowForComponent( this ).repaint();
|
||||||
|
}
|
||||||
|
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||||
label4 = new JLabel();
|
label4 = new JLabel();
|
||||||
@@ -69,6 +135,13 @@ public class ExtrasPanel
|
|||||||
label2 = new JLabel();
|
label2 = new JLabel();
|
||||||
svgIconsPanel = new JPanel();
|
svgIconsPanel = new JPanel();
|
||||||
label3 = new JLabel();
|
label3 = new JLabel();
|
||||||
|
separator1 = new JSeparator();
|
||||||
|
label5 = new JLabel();
|
||||||
|
label6 = new JLabel();
|
||||||
|
rainbowIcon = new JLabel();
|
||||||
|
label7 = new JLabel();
|
||||||
|
redToggleButton = new JToggleButton();
|
||||||
|
brighterToggleButton = new JToggleButton();
|
||||||
|
|
||||||
//======== this ========
|
//======== this ========
|
||||||
setLayout(new MigLayout(
|
setLayout(new MigLayout(
|
||||||
@@ -81,6 +154,10 @@ public class ExtrasPanel
|
|||||||
"[]para" +
|
"[]para" +
|
||||||
"[]" +
|
"[]" +
|
||||||
"[]" +
|
"[]" +
|
||||||
|
"[]" +
|
||||||
|
"[]" +
|
||||||
|
"[]" +
|
||||||
|
"[]" +
|
||||||
"[]"));
|
"[]"));
|
||||||
|
|
||||||
//---- label4 ----
|
//---- label4 ----
|
||||||
@@ -119,6 +196,30 @@ public class ExtrasPanel
|
|||||||
//---- label3 ----
|
//---- label3 ----
|
||||||
label3.setText("The icons may change colors when switching to another theme.");
|
label3.setText("The icons may change colors when switching to another theme.");
|
||||||
add(label3, "cell 1 3 2 1");
|
add(label3, "cell 1 3 2 1");
|
||||||
|
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 2 1");
|
||||||
|
|
||||||
|
//---- label6 ----
|
||||||
|
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 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());
|
||||||
|
add(brighterToggleButton, "cell 1 7 2 1");
|
||||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,5 +231,12 @@ public class ExtrasPanel
|
|||||||
private JLabel label2;
|
private JLabel label2;
|
||||||
private JPanel svgIconsPanel;
|
private JPanel svgIconsPanel;
|
||||||
private JLabel label3;
|
private JLabel label3;
|
||||||
|
private JSeparator separator1;
|
||||||
|
private JLabel label5;
|
||||||
|
private JLabel label6;
|
||||||
|
private JLabel rainbowIcon;
|
||||||
|
private JLabel label7;
|
||||||
|
private JToggleButton redToggleButton;
|
||||||
|
private JToggleButton brighterToggleButton;
|
||||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -6,7 +6,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "insets dialog,hidemode 3"
|
"$layoutConstraints": "insets dialog,hidemode 3"
|
||||||
"$columnConstraints": "[][][left]"
|
"$columnConstraints": "[][][left]"
|
||||||
"$rowConstraints": "[]para[][][]"
|
"$rowConstraints": "[]para[][][][][][][]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "this"
|
name: "this"
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
@@ -56,6 +56,48 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 1 3 2 1"
|
"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: "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"
|
||||||
|
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 ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 0 )
|
"location": new java.awt.Point( 0, 0 )
|
||||||
"size": new java.awt.Dimension( 500, 300 )
|
"size": new java.awt.Dimension( 500, 300 )
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.awt.image.RGBImageFilter;
|
import java.awt.image.RGBImageFilter;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -66,6 +67,8 @@ public class FlatSVGIcon
|
|||||||
private final boolean disabled;
|
private final boolean disabled;
|
||||||
private final ClassLoader classLoader;
|
private final ClassLoader classLoader;
|
||||||
|
|
||||||
|
private ColorFilter colorFilter;
|
||||||
|
|
||||||
private SVGDiagram diagram;
|
private SVGDiagram diagram;
|
||||||
private boolean dark;
|
private boolean dark;
|
||||||
|
|
||||||
@@ -159,13 +162,76 @@ public class FlatSVGIcon
|
|||||||
this( name, -1, -1, scale, false, classLoader );
|
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.name = name;
|
||||||
this.classLoader = classLoader;
|
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.scale = scale;
|
this.scale = scale;
|
||||||
this.disabled = disabled;
|
this.disabled = disabled;
|
||||||
|
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.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -179,7 +245,7 @@ public class FlatSVGIcon
|
|||||||
if( width == this.width && height == this.height )
|
if( width == this.width && height == this.height )
|
||||||
return this;
|
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.diagram = diagram;
|
||||||
icon.dark = dark;
|
icon.dark = dark;
|
||||||
return icon;
|
return icon;
|
||||||
@@ -195,7 +261,7 @@ public class FlatSVGIcon
|
|||||||
if( scale == this.scale )
|
if( scale == this.scale )
|
||||||
return this;
|
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.diagram = diagram;
|
||||||
icon.dark = dark;
|
icon.dark = dark;
|
||||||
return icon;
|
return icon;
|
||||||
@@ -217,6 +283,36 @@ public class FlatSVGIcon
|
|||||||
return icon;
|
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.
|
||||||
|
* <p>
|
||||||
|
* This method accepts a {@link ColorFilter}. Usually you would want to use a ColorFilter created using the
|
||||||
|
* {@link ColorFilter#ColorFilter(Function)} constructor.
|
||||||
|
* <p>
|
||||||
|
* This can be used to brighten colors of the icon:
|
||||||
|
* <pre>icon.setColorFilter( new FlatSVGIcon.ColorFilter( color -> color.brighter() ) );</pre>
|
||||||
|
* <p>
|
||||||
|
* Using a filter, icons can also be turned monochrome (painted with a single color):
|
||||||
|
* <pre>icon.setColorFilter( new FlatSVGIcon.ColorFilter( color -> Color.RED ) );</pre>
|
||||||
|
* <p>
|
||||||
|
* 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() {
|
private void update() {
|
||||||
if( dark == isDarkLaf() && diagram != null )
|
if( dark == isDarkLaf() && diagram != null )
|
||||||
return;
|
return;
|
||||||
@@ -303,7 +399,7 @@ public class FlatSVGIcon
|
|||||||
: GrayFilter.createDisabledIconFilter( dark );
|
: GrayFilter.createDisabledIconFilter( dark );
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), ColorFilter.getInstance(), grayFilter );
|
Graphics2D g2 = new GraphicsFilter( (Graphics2D) g.create(), colorFilter, ColorFilter.getInstance(), grayFilter );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FlatUIUtils.setRenderingHints( g2 );
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
@@ -383,7 +479,7 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
private static Boolean darkLaf;
|
private static Boolean darkLaf;
|
||||||
|
|
||||||
private static boolean isDarkLaf() {
|
public static boolean isDarkLaf() {
|
||||||
if( darkLaf == null ) {
|
if( darkLaf == null ) {
|
||||||
lafChanged();
|
lafChanged();
|
||||||
|
|
||||||
@@ -401,53 +497,253 @@ public class FlatSVGIcon
|
|||||||
|
|
||||||
//---- class ColorFilter --------------------------------------------------
|
//---- class ColorFilter --------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A color filter that can modify colors of a painted {@link FlatSVGIcon}.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* When filtering a color, mappings are applied first, then the mapper function is applied.
|
||||||
|
* <p>
|
||||||
|
* Global {@link FlatSVGIcon} ColorFilter can be retrieved using the {@link ColorFilter#getInstance()} method.
|
||||||
|
*/
|
||||||
public static class ColorFilter
|
public static class ColorFilter
|
||||||
{
|
{
|
||||||
private static ColorFilter instance;
|
private static ColorFilter instance;
|
||||||
|
|
||||||
private final Map<Integer, String> rgb2keyMap = new HashMap<>();
|
private Map<Integer, String> rgb2keyMap;
|
||||||
private final Map<Color, Color> color2colorMap = new HashMap<>();
|
private Map<Color, Color> colorMap;
|
||||||
|
private Map<Color, Color> darkColorMap;
|
||||||
|
private Function<Color, Color> mapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the global ColorFilter that is applied to all icons.
|
||||||
|
*/
|
||||||
public static ColorFilter getInstance() {
|
public static ColorFilter getInstance() {
|
||||||
if( instance == null )
|
if( instance == null ) {
|
||||||
instance = new ColorFilter();
|
instance = new ColorFilter();
|
||||||
|
|
||||||
|
// add default color palette
|
||||||
|
instance.rgb2keyMap = new HashMap<>();
|
||||||
|
for( FlatIconColors c : FlatIconColors.values() )
|
||||||
|
instance.rgb2keyMap.put( c.rgb, c.key );
|
||||||
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty color filter.
|
||||||
|
*/
|
||||||
public ColorFilter() {
|
public ColorFilter() {
|
||||||
for( FlatIconColors c : FlatIconColors.values() )
|
|
||||||
rgb2keyMap.put( c.rgb, c.key );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAll( Map<Color, Color> from2toMap ) {
|
/**
|
||||||
color2colorMap.putAll( from2toMap );
|
* 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.
|
||||||
|
* <p>
|
||||||
|
* Examples:
|
||||||
|
* A ColorFilter can be used to brighten colors of the icon:
|
||||||
|
* <pre>new ColorFilter( color -> color.brighter() );</pre>
|
||||||
|
* <p>
|
||||||
|
* Using a ColorFilter, icons can also be turned monochrome (painted with a single color):
|
||||||
|
* <pre>new ColorFilter( color -> Color.RED );</pre>
|
||||||
|
*
|
||||||
|
* @param mapper The color mapper function
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter( Function<Color, Color> mapper ) {
|
||||||
|
setMapper( mapper );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add( Color from, Color to ) {
|
/**
|
||||||
color2colorMap.put( from, to );
|
* Returns a color modifying function or {@code null}
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public Function<Color, Color> getMapper() {
|
||||||
|
return mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove( Color from ) {
|
/**
|
||||||
color2colorMap.remove( from );
|
* Sets a color modifying function that changes painted colors.
|
||||||
|
* The {@link Function} gets passed the original color and returns a modified one.
|
||||||
|
* <p>
|
||||||
|
* Examples:
|
||||||
|
* A ColorFilter can be used to brighten colors of the icon:
|
||||||
|
* <pre>filter.setMapper( color -> color.brighter() );</pre>
|
||||||
|
* <p>
|
||||||
|
* Using a ColorFilter, icons can also be turned monochrome (painted with a single color):
|
||||||
|
* <pre>filter.setMapper( color -> Color.RED );</pre>
|
||||||
|
*
|
||||||
|
* @param mapper The color mapper function
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public void setMapper( Function<Color, Color> mapper ) {
|
||||||
|
this.mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the color mappings used for light themes.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public Map<Color, Color> getLightColorMap() {
|
||||||
|
return (colorMap != null)
|
||||||
|
? Collections.unmodifiableMap( colorMap )
|
||||||
|
: Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the color mappings used for dark themes.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public Map<Color, Color> getDarkColorMap() {
|
||||||
|
return (darkColorMap != null)
|
||||||
|
? Collections.unmodifiableMap( darkColorMap )
|
||||||
|
: getLightColorMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds color mappings. Used for light and dark themes.
|
||||||
|
*/
|
||||||
|
public ColorFilter addAll( Map<Color, Color> from2toMap ) {
|
||||||
|
ensureColorMap();
|
||||||
|
|
||||||
|
colorMap.putAll( from2toMap );
|
||||||
|
if( darkColorMap != null )
|
||||||
|
darkColorMap.putAll( from2toMap );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a color mappings, which has different colors for light and dark themes.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter addAll( Map<Color, Color> from2toLightMap, Map<Color, Color> from2toDarkMap ) {
|
||||||
|
ensureColorMap();
|
||||||
|
ensureDarkColorMap();
|
||||||
|
|
||||||
|
colorMap.putAll( from2toLightMap );
|
||||||
|
darkColorMap.putAll( from2toDarkMap );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a color mapping. Used for light and dark themes.
|
||||||
|
*/
|
||||||
|
public ColorFilter add( Color from, Color to ) {
|
||||||
|
ensureColorMap();
|
||||||
|
|
||||||
|
colorMap.put( from, to );
|
||||||
|
if( darkColorMap != null )
|
||||||
|
darkColorMap.put( from, to );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a color mapping, which has different colors for light and dark themes.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter add( Color from, Color toLight, Color toDark ) {
|
||||||
|
ensureColorMap();
|
||||||
|
ensureDarkColorMap();
|
||||||
|
|
||||||
|
if( toLight != null )
|
||||||
|
colorMap.put( from, toLight );
|
||||||
|
if( toDark != null )
|
||||||
|
darkColorMap.put( from, toDark );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a specific color mapping.
|
||||||
|
*/
|
||||||
|
public ColorFilter remove( Color from ) {
|
||||||
|
if( colorMap != null )
|
||||||
|
colorMap.remove( from );
|
||||||
|
if( darkColorMap != null )
|
||||||
|
darkColorMap.remove( from );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all color mappings.
|
||||||
|
*
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public ColorFilter removeAll() {
|
||||||
|
colorMap = null;
|
||||||
|
darkColorMap = null;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureColorMap() {
|
||||||
|
if( colorMap == null )
|
||||||
|
colorMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureDarkColorMap() {
|
||||||
|
if( darkColorMap == null )
|
||||||
|
darkColorMap = new HashMap<>( colorMap );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color filter( Color color ) {
|
public Color filter( Color color ) {
|
||||||
Color newColor = color2colorMap.get( color );
|
// apply mappings
|
||||||
if( newColor != null )
|
color = applyMappings( color );
|
||||||
return newColor;
|
|
||||||
|
|
||||||
String colorKey = rgb2keyMap.get( color.getRGB() & 0xffffff );
|
// apply mapper function
|
||||||
if( colorKey == null )
|
if( mapper != null )
|
||||||
return color;
|
color = mapper.apply( color );
|
||||||
|
|
||||||
newColor = UIManager.getColor( colorKey );
|
return color;
|
||||||
if( newColor == null )
|
|
||||||
return color;
|
|
||||||
|
|
||||||
return (newColor.getAlpha() != color.getAlpha())
|
|
||||||
? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) )
|
|
||||||
: newColor;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private Color applyMappings( Color color ) {
|
||||||
|
if( colorMap != null ) {
|
||||||
|
Map<Color, Color> map = (darkColorMap != null && isDarkLaf()) ? darkColorMap : colorMap;
|
||||||
|
Color newColor = map.get( color );
|
||||||
|
if( newColor != null )
|
||||||
|
return newColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
Color newColor = UIManager.getColor( colorKey );
|
||||||
|
if( newColor == null )
|
||||||
|
return color;
|
||||||
|
|
||||||
|
// preserve alpha of original color
|
||||||
|
return (newColor.getAlpha() != color.getAlpha())
|
||||||
|
? new Color( (newColor.getRGB() & 0x00ffffff) | (color.getRGB() & 0xff000000) )
|
||||||
|
: newColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)}.
|
||||||
|
*
|
||||||
|
* @see GrayFilter
|
||||||
|
* @since 1.2
|
||||||
|
*/
|
||||||
|
public static Function<Color, Color> createRGBImageFilterFunction( RGBImageFilter rgbImageFilter ) {
|
||||||
|
return color -> {
|
||||||
|
int oldRGB = color.getRGB();
|
||||||
|
int newRGB = rgbImageFilter.filterRGB( 0, 0, oldRGB );
|
||||||
|
return (newRGB != oldRGB) ? new Color( newRGB, true ) : color;
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class GraphicsFilter -----------------------------------------------
|
//---- class GraphicsFilter -----------------------------------------------
|
||||||
@@ -456,11 +752,15 @@ public class FlatSVGIcon
|
|||||||
extends Graphics2DProxy
|
extends Graphics2DProxy
|
||||||
{
|
{
|
||||||
private final ColorFilter colorFilter;
|
private final ColorFilter colorFilter;
|
||||||
|
private final ColorFilter globalColorFilter;
|
||||||
private final RGBImageFilter grayFilter;
|
private final RGBImageFilter grayFilter;
|
||||||
|
|
||||||
public GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter, RGBImageFilter grayFilter ) {
|
GraphicsFilter( Graphics2D delegate, ColorFilter colorFilter,
|
||||||
|
ColorFilter globalColorFilter, RGBImageFilter grayFilter )
|
||||||
|
{
|
||||||
super( delegate );
|
super( delegate );
|
||||||
this.colorFilter = colorFilter;
|
this.colorFilter = colorFilter;
|
||||||
|
this.globalColorFilter = globalColorFilter;
|
||||||
this.grayFilter = grayFilter;
|
this.grayFilter = grayFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,8 +777,14 @@ public class FlatSVGIcon
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Color filterColor( Color color ) {
|
private Color filterColor( Color color ) {
|
||||||
if( colorFilter != null )
|
if( colorFilter != null ) {
|
||||||
color = colorFilter.filter( color );
|
Color newColor = colorFilter.filter( color );
|
||||||
|
color = (newColor != color)
|
||||||
|
? newColor
|
||||||
|
: globalColorFilter.filter( color );
|
||||||
|
} else
|
||||||
|
color = globalColorFilter.filter( color );
|
||||||
|
|
||||||
if( grayFilter != null ) {
|
if( grayFilter != null ) {
|
||||||
int oldRGB = color.getRGB();
|
int oldRGB = color.getRGB();
|
||||||
int newRGB = grayFilter.filterRGB( 0, 0, oldRGB );
|
int newRGB = grayFilter.filterRGB( 0, 0, oldRGB );
|
||||||
|
|||||||
Reference in New Issue
Block a user