diff --git a/CHANGELOG.md b/CHANGELOG.md index c38b53b7..093fb20e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ FlatLaf Change Log - TabbedPane: Support closable tabs. (issues #31 and #40) - Support painting separator line between window title and content (use UI value `TitlePane.borderColor`). (issue #184) +- Extras: `FlatSVGIcon` now allows specifying icon width and height in + constructors. (issue #196) #### Fixed bugs 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 a963c6a9..6876a19c 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 @@ -41,6 +41,8 @@ import com.kitfox.svg.SVGException; import com.kitfox.svg.SVGUniverse; /** + * An icon that loads and paints SVG. + * * @author Karl Tauber */ public class FlatSVGIcon @@ -50,18 +52,137 @@ public class FlatSVGIcon private static final SVGUniverse svgUniverse = new SVGUniverse(); private final String name; + private final int width; + private final int height; + private final float scale; private final ClassLoader classLoader; private SVGDiagram diagram; private boolean dark; + /** + * Creates an SVG icon from the given resource name. + *

+ * The SVG attributes {@code width} and {@code height} (or {@code viewBox}) + * in the tag {@code } are used as icon size. + * + * @param name the name of the SVG resource (a '/'-separated path) + * @see ClassLoader#getResource(String) + */ public FlatSVGIcon( String name ) { - this( name, null ); + this( name, -1, -1, 1, null ); } + /** + * Creates an SVG icon from the given resource name. + * The SVG file is loaded from the given class loader. + *

+ * The SVG attributes {@code width} and {@code height} (or {@code viewBox}) + * in the tag {@code } are used as icon size. + * + * @param name the name of the SVG resource (a '/'-separated path) + * @param classLoader the class loader used to load the SVG resource + * @see ClassLoader#getResource(String) + */ public FlatSVGIcon( String name, ClassLoader classLoader ) { + this( name, -1, -1, 1, classLoader ); + } + + /** + * Creates an SVG icon from the given resource name with the given width and height. + *

+ * The icon is scaled if the given size is different to the size specified in the SVG file. + * + * @param name the name of the SVG resource (a '/'-separated path) + * @param width the width of the icon + * @param height the height of the icon + * @see ClassLoader#getResource(String) + */ + public FlatSVGIcon( String name, int width, int height ) { + this( name, width, height, 1, null ); + } + + /** + * Creates an SVG icon from the given resource name with the given width and height. + * The SVG file is loaded from the given class loader. + *

+ * The icon is scaled if the given size is different to the size specified in the SVG file. + * + * @param name the name of the SVG resource (a '/'-separated path) + * @param width the width of the icon + * @param height the height of the icon + * @param classLoader the class loader used to load the SVG resource + * @see ClassLoader#getResource(String) + */ + public FlatSVGIcon( String name, int width, int height, ClassLoader classLoader ) { + this( name, width, height, 1, classLoader ); + } + + /** + * Creates an SVG icon from the given resource name that is scaled by the given amount. + *

+ * The SVG attributes {@code width} and {@code height} (or {@code viewBox}) + * in the tag {@code } are used as base icon size, which is multiplied + * by the given scale factor. + * + * @param name the name of the SVG resource (a '/'-separated path) + * @param scale the amount by which the icon size is scaled + * @see ClassLoader#getResource(String) + */ + public FlatSVGIcon( String name, float scale ) { + this( name, -1, -1, scale, null ); + } + + /** + * Creates an SVG icon from the given resource name that is scaled by the given amount. + * The SVG file is loaded from the given class loader. + *

+ * The SVG attributes {@code width} and {@code height} (or {@code viewBox}) + * in the tag {@code } are used as base icon size, which is multiplied + * by the given scale factor. + * + * @param name the name of the SVG resource (a '/'-separated path) + * @param scale the amount by which the icon size is scaled + * @param classLoader the class loader used to load the SVG resource + * @see ClassLoader#getResource(String) + */ + public FlatSVGIcon( String name, float scale, ClassLoader classLoader ) { + this( name, -1, -1, scale, classLoader ); + } + + private FlatSVGIcon( String name, int width, int height, float scale, ClassLoader classLoader ) { this.name = name; this.classLoader = classLoader; + this.width = width; + this.height = height; + this.scale = scale; + } + + /** + * Creates a new icon with given width and height, which is derived from this icon. + * + * @param width the width of the new icon + * @param height the height of the new icon + * @return a new icon + */ + public FlatSVGIcon derive( int width, int height ) { + FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, classLoader ); + icon.diagram = diagram; + icon.dark = dark; + return icon; + } + + /** + * Creates a new icon with given scaling, which is derived from this icon. + * + * @param scale the amount by which the icon size is scaled + * @return a new icon + */ + public FlatSVGIcon derive( float scale ) { + FlatSVGIcon icon = new FlatSVGIcon( name, width, height, scale, classLoader ); + icon.diagram = diagram; + icon.dark = dark; + return icon; } private void update() { @@ -91,27 +212,52 @@ public class FlatSVGIcon return cl.getResource( name ); } + /** + * Returns whether the SVG file was found. + * + * @return whether the SVG file was found + */ public boolean hasFound() { update(); return diagram != null; } + /** + * Returns the scaled width of the icon. + */ @Override public int getIconWidth() { + if( width > 0 ) + return scaleSize( width ); + update(); - return (int) UIScale.scale( (diagram != null) ? diagram.getWidth() : 16 ); + return scaleSize( (diagram != null) ? Math.round( diagram.getWidth() ) : 16 ); } + /** + * Returns the scaled height of the icon. + */ @Override public int getIconHeight() { + if( height > 0 ) + return scaleSize( height ); + update(); - return (int) UIScale.scale( (diagram != null) ? diagram.getHeight() : 16 ); + return scaleSize( (diagram != null) ? Math.round( diagram.getHeight() ) : 16 ); + } + + private int scaleSize( int size ) { + int scaledSize = UIScale.scale( size ); + if( scale != 1 ) + scaledSize = Math.round( scaledSize * scale ); + return scaledSize; } @Override public void paintIcon( Component c, Graphics g, int x, int y ) { update(); + // check whether icon is outside of clipping area Rectangle clipBounds = g.getClipBounds(); if( clipBounds != null && !clipBounds.intersects( new Rectangle( x, y, getIconWidth(), getIconHeight() ) ) ) return; @@ -147,6 +293,14 @@ public class FlatSVGIcon g.clipRect( 0, 0, getIconWidth(), getIconHeight() ); UIScale.scaleGraphics( g ); + if( width > 0 || height > 0 ) { + double sx = (width > 0) ? width / diagram.getWidth() : 1; + double sy = (height > 0) ? height / diagram.getHeight() : 1; + if( sx != 1 || sy != 1 ) + g.scale( sx, sy ); + } + if( scale != 1 ) + g.scale( scale, scale ); diagram.setIgnoringClipHeuristic( true );