Browse Source

Back svg icons by cached renderer image.

pull/170/head
weisj 5 years ago
parent
commit
f2f70f412e
  1. 23
      core/src/main/java/com/github/weisj/darklaf/graphics/ImageUtil.java
  2. 4
      core/src/main/java/com/github/weisj/darklaf/ui/list/DarkListCellRendererDelegate.java
  3. 47
      property-loader/src/main/java/com/github/weisj/darklaf/icons/DarkSVGIcon.java
  4. 36
      property-loader/src/main/java/com/github/weisj/darklaf/icons/ImageSource.java
  5. 13
      property-loader/src/main/java/com/github/weisj/darklaf/icons/ThemedSVGIcon.java
  6. 21
      utils/src/main/java/com/github/weisj/darklaf/util/Scale.java

23
core/src/main/java/com/github/weisj/darklaf/graphics/ImageUtil.java

@ -29,6 +29,7 @@ import java.awt.image.BufferedImage;
import javax.swing.*; import javax.swing.*;
import com.github.weisj.darklaf.icons.ImageSource;
import com.github.weisj.darklaf.util.Scale; import com.github.weisj.darklaf.util.Scale;
/** /**
@ -45,8 +46,8 @@ public final class ImageUtil {
int w = icon.getIconWidth(); int w = icon.getIconWidth();
int h = icon.getIconHeight(); int h = icon.getIconHeight();
GraphicsConfiguration gc = c.getGraphicsConfiguration(); GraphicsConfiguration gc = c.getGraphicsConfiguration();
double sx = gc != null ? Scale.getScaleX(gc) : Scale.SCALE_X; double sx = Scale.getScaleX(gc);
double sy = gc != null ? Scale.getScaleY(gc) : Scale.SCALE_Y; double sy = Scale.getScaleY(gc);
double scaleX = sx * (((double) FRAME_ICON_SIZE) / w); double scaleX = sx * (((double) FRAME_ICON_SIZE) / w);
double scaleY = sy * (((double) FRAME_ICON_SIZE) / h); double scaleY = sy * (((double) FRAME_ICON_SIZE) / h);
return createScaledImage(icon, scaleX, scaleY); return createScaledImage(icon, scaleX, scaleY);
@ -56,13 +57,17 @@ public final class ImageUtil {
if (icon == null) return null; if (icon == null) return null;
int w = (int) (scalex * icon.getIconWidth()); int w = (int) (scalex * icon.getIconWidth());
int h = (int) (scaley * icon.getIconHeight()); int h = (int) (scaley * icon.getIconHeight());
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); if (icon instanceof ImageSource) {
return ((ImageSource) icon).createImage(w, h);
} else {
BufferedImage image = createCompatibleTranslucentImage(w, h);
Graphics2D g = (Graphics2D) image.getGraphics(); Graphics2D g = (Graphics2D) image.getGraphics();
g.scale(scalex, scaley); g.scale(scalex, scaley);
icon.paintIcon(null, g, 0, 0); icon.paintIcon(null, g, 0, 0);
g.dispose(); g.dispose();
return image; return image;
} }
}
public static Image createDragImage(final Component c, final int lw, final Color borderColor) { public static Image createDragImage(final Component c, final int lw, final Color borderColor) {
return createDragImage(c, new Rectangle(0, 0, c.getWidth(), c.getHeight()), lw, borderColor); return createDragImage(c, new Rectangle(0, 0, c.getWidth(), c.getHeight()), lw, borderColor);
@ -130,10 +135,9 @@ public final class ImageUtil {
BufferedImage image; BufferedImage image;
boolean scale = scalex != 1.0 || scaley != 1.0; boolean scale = scalex != 1.0 || scaley != 1.0;
if (scale) { if (scale) {
image = new BufferedImage((int) (scalex * bounds.width), (int) (scaley * bounds.height), image = createCompatibleImage((int) (scalex * bounds.width), (int) (scaley * bounds.height));
BufferedImage.TYPE_INT_RGB);
} else { } else {
image = new BufferedImage(bounds.width, bounds.height, BufferedImage.TYPE_INT_RGB); image = createCompatibleImage(bounds.width, bounds.height);
} }
final Graphics2D g2d = (Graphics2D) image.getGraphics(); final Graphics2D g2d = (Graphics2D) image.getGraphics();
if (scale) { if (scale) {
@ -150,6 +154,13 @@ public final class ImageUtil {
return image; return image;
} }
public static BufferedImage createCompatibleImage(final int width,
final int height) {
return isHeadless() ? new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
: getGraphicsConfiguration().createCompatibleImage(width, height,
Transparency.OPAQUE);
}
public static BufferedImage createCompatibleTranslucentImage(final int width, public static BufferedImage createCompatibleTranslucentImage(final int width,
final int height) { final int height) {
return isHeadless() ? new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) return isHeadless() ? new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)

4
core/src/main/java/com/github/weisj/darklaf/ui/list/DarkListCellRendererDelegate.java

@ -28,8 +28,6 @@ import java.awt.*;
import javax.swing.*; import javax.swing.*;
import org.jdesktop.swingx.renderer.DefaultListRenderer;
import com.github.weisj.darklaf.delegate.ListCellRendererDelegate; import com.github.weisj.darklaf.delegate.ListCellRendererDelegate;
import com.github.weisj.darklaf.ui.cell.CellUtil; import com.github.weisj.darklaf.ui.cell.CellUtil;
import com.github.weisj.darklaf.util.PropertyUtil; import com.github.weisj.darklaf.util.PropertyUtil;
@ -43,7 +41,7 @@ public class DarkListCellRendererDelegate extends ListCellRendererDelegate<Objec
@Override @Override
public void setDelegate(final ListCellRenderer<Object> delegate) { public void setDelegate(final ListCellRenderer<Object> delegate) {
if (delegate == null) { if (delegate == null) {
super.setDelegate(new DefaultListRenderer()); super.setDelegate(new DefaultListCellRenderer());
} else { } else {
super.setDelegate(delegate); super.setDelegate(delegate);
} }

47
property-loader/src/main/java/com/github/weisj/darklaf/icons/DarkSVGIcon.java

@ -30,9 +30,8 @@ import java.net.URI;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.swing.*;
import com.github.weisj.darklaf.util.LogUtil; import com.github.weisj.darklaf.util.LogUtil;
import com.github.weisj.darklaf.util.Scale;
import com.kitfox.svg.app.beans.SVGIcon; import com.kitfox.svg.app.beans.SVGIcon;
/** /**
@ -41,13 +40,16 @@ import com.kitfox.svg.app.beans.SVGIcon;
* @author Jannis Weis * @author Jannis Weis
* @since 2019 * @since 2019
*/ */
public class DarkSVGIcon implements DerivableIcon<DarkSVGIcon>, RotateIcon, Serializable { public class DarkSVGIcon implements DerivableIcon<DarkSVGIcon>, RotateIcon, Serializable, ImageSource {
private static final Logger LOGGER = LogUtil.getLogger(DarkSVGIcon.class); private static final Logger LOGGER = LogUtil.getLogger(DarkSVGIcon.class);
private final Dimension size; private final Dimension size;
private final SVGIcon icon; private final SVGIcon icon;
private final URI uri; protected final URI uri;
private final AtomicBoolean loaded; private final AtomicBoolean loaded;
private double scaleX;
private double scaleY;
private Image image;
/** /**
* Method to fetch the SVG icon from a url. * Method to fetch the SVG icon from a url.
@ -83,16 +85,38 @@ public class DarkSVGIcon implements DerivableIcon<DarkSVGIcon>, RotateIcon, Seri
@Override @Override
public void paintIcon(final Component c, final Graphics g, final int x, final int y) { public void paintIcon(final Component c, final Graphics g, final int x, final int y) {
ensureLoaded();
paintIcon(c, g, x, y, 0); paintIcon(c, g, x, y, 0);
} }
private void ensureLoaded() { protected boolean ensureLoaded() {
if (!loaded.get()) { if (!loaded.get()) {
LOGGER.fine(() -> "Loading icon '" + uri.toASCIIString() + "'."); LOGGER.fine(() -> "Loading icon '" + uri.toASCIIString() + "'.");
icon.setSvgURI(uri); icon.setSvgURI(uri);
loaded.set(true); loaded.set(true);
return true;
}
return false;
}
protected void updateCache(final boolean update, final Component c) {
GraphicsConfiguration gc = c != null ? c.getGraphicsConfiguration() : null;
double sx = Scale.getScaleX(gc);
double sy = Scale.getScaleY(gc);
if (!update && Scale.equalWithError(scaleX, sx) && Scale.equalWithError(scaleY, sy) && image != null) return;
scaleX = sx;
scaleY = sy;
image = createImage(Scale.scale(scaleX, scaleY, size));
}
@Override
public Image createImage(final Dimension size) {
ensureLoaded();
icon.setPreferredSize(size);
return icon.getImage();
} }
protected void ensureImageLoaded(final Component c) {
updateCache(ensureLoaded(), c);
} }
protected SVGIcon createSVGIcon() { protected SVGIcon createSVGIcon() {
@ -102,14 +126,17 @@ public class DarkSVGIcon implements DerivableIcon<DarkSVGIcon>, RotateIcon, Seri
@Override @Override
public void paintIcon(final Component c, final Graphics g, final int x, final int y, public void paintIcon(final Component c, final Graphics g, final int x, final int y,
final double rotation) { final double rotation) {
ensureLoaded(); ensureImageLoaded(c);
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
g2.translate(x, y); g2.translate(x, y);
double sx = size.width / (double) image.getWidth(null);
double sy = size.height / (double) image.getWidth(null);
g2.scale(sx, sy);
if (rotation != 0) { if (rotation != 0) {
g2.rotate(rotation, size.width / 2.0, size.height / 2.0); g2.rotate(rotation, size.width / 2.0, size.height / 2.0);
} }
icon.setPreferredSize(size); g2.drawImage(image, 0, 0, null);
icon.paintIcon(c, g2, 0, 0); g2.scale(1 / sx, 1 / sy);
g2.translate(-x, -y); g2.translate(-x, -y);
} }
@ -124,7 +151,7 @@ public class DarkSVGIcon implements DerivableIcon<DarkSVGIcon>, RotateIcon, Seri
} }
public SVGIcon getSVGIcon() { public SVGIcon getSVGIcon() {
ensureLoaded(); if (!loaded.get()) ensureLoaded();
return icon; return icon;
} }
} }

36
property-loader/src/main/java/com/github/weisj/darklaf/icons/ImageSource.java

@ -0,0 +1,36 @@
/*
* MIT License
*
* Copyright (c) 2020 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package com.github.weisj.darklaf.icons;
import java.awt.*;
public interface ImageSource {
Image createImage(final Dimension size);
default Image createImage(final int width, final int height) {
return createImage(new Dimension(width, height));
}
}

13
property-loader/src/main/java/com/github/weisj/darklaf/icons/ThemedSVGIcon.java

@ -39,18 +39,21 @@ public class ThemedSVGIcon extends DarkSVGIcon {
currentTheme = new Object(); currentTheme = new Object();
} }
@Override protected boolean ensureLoaded() {
public void paintIcon(final Component c, final Graphics g, final int x, final int y, final double rotation) { /*
ensureTheme(); * Use non-short-circuiting operand here to ensure the colors are actually patched.
super.paintIcon(c, g, x, y, rotation); */
return super.ensureLoaded() | ensureTheme();
} }
private void ensureTheme() { protected boolean ensureTheme() {
Object theme = IconLoader.getThemeStatus(); Object theme = IconLoader.getThemeStatus();
if (currentTheme != theme) { if (currentTheme != theme) {
patchColors(); patchColors();
currentTheme = theme; currentTheme = theme;
return true;
} }
return false;
} }
protected void patchColors() { protected void patchColors() {

21
utils/src/main/java/com/github/weisj/darklaf/util/Scale.java

@ -31,6 +31,7 @@ public class Scale {
public static final double SCALE; public static final double SCALE;
public static final double SCALE_X; public static final double SCALE_X;
public static final double SCALE_Y; public static final double SCALE_Y;
private static final double EPSILON = 0.0001;
static { static {
DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode(); DisplayMode mode = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode();
@ -41,11 +42,13 @@ public class Scale {
} }
public static double scaleWidth(final double value, final GraphicsConfiguration gc) { public static double scaleWidth(final double value, final GraphicsConfiguration gc) {
if (gc == null) return scaleWidth(value);
AffineTransform transform = gc.getDefaultTransform(); AffineTransform transform = gc.getDefaultTransform();
return transform.getScaleX() * value; return transform.getScaleX() * value;
} }
public static double scaleHeight(final double value, final GraphicsConfiguration gc) { public static double scaleHeight(final double value, final GraphicsConfiguration gc) {
if (gc == null) return scaleHeight(value);
AffineTransform transform = gc.getDefaultTransform(); AffineTransform transform = gc.getDefaultTransform();
return transform.getScaleY() * value; return transform.getScaleY() * value;
} }
@ -83,10 +86,28 @@ public class Scale {
} }
public static double getScaleX(final GraphicsConfiguration gc) { public static double getScaleX(final GraphicsConfiguration gc) {
if (gc == null) return SCALE_X;
return gc.getDefaultTransform().getScaleX(); return gc.getDefaultTransform().getScaleX();
} }
public static double getScaleY(final GraphicsConfiguration gc) { public static double getScaleY(final GraphicsConfiguration gc) {
if (gc == null) return SCALE_Y;
return gc.getDefaultTransform().getScaleY(); return gc.getDefaultTransform().getScaleY();
} }
public static Dimension scale(final GraphicsConfiguration gc, final Dimension size) {
return new Dimension((int) scaleWidth(size.width, gc), (int) scaleHeight(size.height, gc));
}
public static double scale(final double scale, final double value) {
return scale * value;
}
public static Dimension scale(final double scaleX, final double scaleY, final Dimension size) {
return new Dimension((int) scale(scaleX, size.width), (int) scale(scaleY, size.height));
}
public static boolean equalWithError(final double a, final double b) {
return Math.abs(a - b) < EPSILON;
}
} }

Loading…
Cancel
Save