diff --git a/change_notes.md b/change_notes.md index ee86b0e3..27d085af 100644 --- a/change_notes.md +++ b/change_notes.md @@ -6,7 +6,7 @@ - Added utility method to create themed frame icons that change depending on the current theme: ````java - frame.setIconImage(ImageUtil.createFrameIcon(icon, frame)); + window.setIconImage(IconLoader.createFrameIcon(icon, window)); ```` - The value of `ButtonConstants.KEY_SQUARE` no longer affects the arc size of buttons. - If a button specifies the `ButtonConstants.VARIANT_BORDERLESS` style it no longer has a default margin of the focus border size. @@ -34,3 +34,4 @@ - Popups show up at the wrong location after moving the frame to a screen with a different `GraphicsConfiguration`. 995da5a2325fad4e3873388a215bbb345a779658 - The value of `ComboBox.selectionBackground` isn't respected. 6b9fa9f1596bbf90914d7008c4d49fc43f3efb94 - `JTree` doesn't paint the full background if repainted area lies outside of the row bounds. 4e5fe2a6faea05e9315bc1e9b30d7cec92ce9e6b +- Tooltips have an incorrect position in some scenarios. a42f4bbbaa1c8d245efc1b95ad56e3c9aec6701d diff --git a/core/src/main/java/com/github/weisj/darklaf/components/border/DropShadowBorder.java b/core/src/main/java/com/github/weisj/darklaf/components/border/DropShadowBorder.java index 2c84e06d..16b382d2 100644 --- a/core/src/main/java/com/github/weisj/darklaf/components/border/DropShadowBorder.java +++ b/core/src/main/java/com/github/weisj/darklaf/components/border/DropShadowBorder.java @@ -36,8 +36,8 @@ import java.util.Map; import javax.swing.border.Border; -import com.github.weisj.darklaf.graphics.ImageUtil; import com.github.weisj.darklaf.util.Disposable; +import com.github.weisj.darklaf.util.ImageUtil; /** * Implements a DropShadow for components. In general, the DropShadowBorder will work with any rectangular components diff --git a/core/src/main/java/com/github/weisj/darklaf/settings/ThemeSettings.java b/core/src/main/java/com/github/weisj/darklaf/settings/ThemeSettings.java index 23836a45..9ea53d54 100644 --- a/core/src/main/java/com/github/weisj/darklaf/settings/ThemeSettings.java +++ b/core/src/main/java/com/github/weisj/darklaf/settings/ThemeSettings.java @@ -32,7 +32,7 @@ import javax.swing.*; import com.github.weisj.darklaf.LafManager; import com.github.weisj.darklaf.components.DefaultButton; -import com.github.weisj.darklaf.graphics.ImageUtil; +import com.github.weisj.darklaf.icons.IconLoader; import com.github.weisj.darklaf.theme.Theme; import com.github.weisj.darklaf.theme.event.ThemePreferenceChangeEvent; import com.github.weisj.darklaf.theme.event.ThemePreferenceListener; @@ -91,7 +91,7 @@ public class ThemeSettings implements ThemePreferenceListener { protected JDialog createDialog(final Window parent) { JDialog dialog = new JDialog(parent); - dialog.setIconImage(ImageUtil.createFrameIcon(getIcon(), dialog)); + dialog.setIconImage(IconLoader.createFrameIcon(getIcon(), dialog)); dialog.setTitle(settingsPanel.getTitle()); dialog.setContentPane(contentPane); dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); diff --git a/core/src/main/java/com/github/weisj/darklaf/task/UtilityDefaultsInitTask.java b/core/src/main/java/com/github/weisj/darklaf/task/UtilityDefaultsInitTask.java index 165c319f..4ce20d09 100644 --- a/core/src/main/java/com/github/weisj/darklaf/task/UtilityDefaultsInitTask.java +++ b/core/src/main/java/com/github/weisj/darklaf/task/UtilityDefaultsInitTask.java @@ -53,10 +53,11 @@ public class UtilityDefaultsInitTask implements DefaultsInitTask { PaintUtil.setFocusInactiveGlow(defaults.getColor("glowFocusInactive")); PaintUtil.setWarningGlow(defaults.getColor("glowWarning")); + CellUtil.updateColors(defaults); + IconLoader.updateAwareStyle(Theme.isDark(currentTheme) ? AwareIconStyle.DARK : AwareIconStyle.LIGHT); IconLoader.updateThemeStatus(currentTheme); - - CellUtil.updateColors(defaults); + IconLoader.reloadFrameIcons(); } private float getOpacity(final UIDefaults defaults, final String key) { diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneTransferHandler.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneTransferHandler.java index 843fe840..a3264731 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneTransferHandler.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabbedpane/TabbedPaneTransferHandler.java @@ -35,7 +35,7 @@ import java.awt.event.MouseEvent; import javax.swing.*; import javax.swing.plaf.TabbedPaneUI; -import com.github.weisj.darklaf.graphics.ImageUtil; +import com.github.weisj.darklaf.util.DnDUtil; /** * @author Robert Futrell @@ -166,7 +166,7 @@ public class TabbedPaneTransferHandler extends TransferHandler implements DropTa protected void createDragImage(final JTabbedPane tabbedPane, final DarkTabbedPaneUI ui) { Color color = ui != null ? ui.getDragBorderColor() : tabbedPane.getBackgroundAt(currentTransferable.transferData.tabIndex); - Image tabImage = ImageUtil.createDragImage(tabbedPane, currentTransferable.transferData.tabBounds, 2, color); + Image tabImage = DnDUtil.createDragImage(tabbedPane, currentTransferable.transferData.tabBounds, 2, color); int w = tabImage.getWidth(null); int h = tabImage.getHeight(null); setDragImageOffset(new Point(w / 2, h / 2)); diff --git a/core/src/main/java/com/github/weisj/darklaf/ui/tabframe/TabFrameTransferHandler.java b/core/src/main/java/com/github/weisj/darklaf/ui/tabframe/TabFrameTransferHandler.java index 44be08da..9bb7c0b6 100644 --- a/core/src/main/java/com/github/weisj/darklaf/ui/tabframe/TabFrameTransferHandler.java +++ b/core/src/main/java/com/github/weisj/darklaf/ui/tabframe/TabFrameTransferHandler.java @@ -38,8 +38,8 @@ import com.github.weisj.darklaf.components.tabframe.JTabFrame; import com.github.weisj.darklaf.components.tabframe.TabFramePopup; import com.github.weisj.darklaf.components.tabframe.TabFrameTab; import com.github.weisj.darklaf.components.tabframe.TabFrameUI; -import com.github.weisj.darklaf.graphics.ImageUtil; import com.github.weisj.darklaf.util.Alignment; +import com.github.weisj.darklaf.util.DnDUtil; /** * @author Jannis Weis @@ -298,7 +298,7 @@ public class TabFrameTransferHandler extends TransferHandler implements DropTarg protected void createDragImage(final TabFrameUI ui) { Component comp = currentTransferable.transferData.tab.getComponent(); - Image tabImage = ImageUtil.createDragImage(comp, 2, ui.getDragBorderColor()); + Image tabImage = DnDUtil.createDragImage(comp, 2, ui.getDragBorderColor()); int w = tabImage.getWidth(null); int h = tabImage.getHeight(null); setDragImageOffset(new Point(w / 2, h / 2)); diff --git a/core/src/main/java/com/github/weisj/darklaf/util/DnDUtil.java b/core/src/main/java/com/github/weisj/darklaf/util/DnDUtil.java new file mode 100644 index 00000000..36682b22 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/util/DnDUtil.java @@ -0,0 +1,49 @@ +/* + * 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.util; + +import java.awt.*; + +import com.github.weisj.darklaf.graphics.PaintUtil; + +public class DnDUtil { + + 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); + } + + public static Image createDragImage(final Component c, final Rectangle bounds, + final int lw, final Color borderColor) { + Image tabImage = ImageUtil.scaledImageFromComponent(c, bounds); + int w = tabImage.getWidth(null); + int h = tabImage.getHeight(null); + Graphics g = tabImage.getGraphics(); + + g.setColor(borderColor); + PaintUtil.drawRect(g, 0, 0, w, h, lw); + g.dispose(); + return tabImage; + } +} diff --git a/core/src/test/java/documentation/CreateUITable.java b/core/src/test/java/documentation/CreateUITable.java index 9fbf3c24..47260fbf 100644 --- a/core/src/test/java/documentation/CreateUITable.java +++ b/core/src/test/java/documentation/CreateUITable.java @@ -45,11 +45,11 @@ import com.github.weisj.darklaf.DarkLaf; import com.github.weisj.darklaf.LafManager; import com.github.weisj.darklaf.PropertyLoader; import com.github.weisj.darklaf.components.border.DropShadowBorder; -import com.github.weisj.darklaf.graphics.ImageUtil; import com.github.weisj.darklaf.icons.DarkSVGIcon; import com.github.weisj.darklaf.icons.EmptyIcon; import com.github.weisj.darklaf.theme.Theme; import com.github.weisj.darklaf.util.*; +import com.github.weisj.darklaf.util.ImageUtil; import com.kitfox.svg.app.beans.SVGIcon; import defaults.SampleRenderer; diff --git a/core/src/test/java/test/AbstractImageTest.java b/core/src/test/java/test/AbstractImageTest.java index 8b5c312f..7eadb737 100644 --- a/core/src/test/java/test/AbstractImageTest.java +++ b/core/src/test/java/test/AbstractImageTest.java @@ -31,9 +31,8 @@ import java.io.IOException; import java.nio.file.Files; import javax.imageio.ImageIO; -import javax.swing.*; -import com.github.weisj.darklaf.graphics.ImageUtil; +import com.github.weisj.darklaf.util.ImageUtil; public abstract class AbstractImageTest { private static final int SCALING_FACTOR = 3; diff --git a/core/src/test/java/ui/ComponentDemo.java b/core/src/test/java/ui/ComponentDemo.java index 81547e6c..4b5a149e 100644 --- a/core/src/test/java/ui/ComponentDemo.java +++ b/core/src/test/java/ui/ComponentDemo.java @@ -38,8 +38,8 @@ import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import com.github.weisj.darklaf.LafManager; -import com.github.weisj.darklaf.graphics.ImageUtil; import com.github.weisj.darklaf.graphics.StringPainter; +import com.github.weisj.darklaf.icons.IconLoader; import com.github.weisj.darklaf.settings.ThemeSettingsMenuItem; import com.github.weisj.darklaf.theme.Theme; import com.github.weisj.darklaf.theme.info.PreferredThemeStyle; @@ -90,7 +90,7 @@ public interface ComponentDemo { Icon icon = demo.getFrameIcon(); if (icon != null) { - window.setIconImage(ImageUtil.createFrameIcon(icon, window)); + window.setIconImage(IconLoader.createFrameIcon(icon, window)); } window.pack(); diff --git a/property-loader/build.gradle.kts b/property-loader/build.gradle.kts index 87d3134a..453320d9 100644 --- a/property-loader/build.gradle.kts +++ b/property-loader/build.gradle.kts @@ -5,4 +5,10 @@ plugins { dependencies { api(project(":darklaf-utils")) implementation("com.formdev:svgSalamander") + testImplementation("org.junit.jupiter:junit-jupiter-api") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") +} + +tasks.test { + useJUnitPlatform() } diff --git a/property-loader/src/main/java/com/github/weisj/darklaf/icons/DynamicIcon.java b/property-loader/src/main/java/com/github/weisj/darklaf/icons/DynamicIcon.java new file mode 100644 index 00000000..123961f5 --- /dev/null +++ b/property-loader/src/main/java/com/github/weisj/darklaf/icons/DynamicIcon.java @@ -0,0 +1,29 @@ +/* + * 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 javax.swing.*; + +public interface DynamicIcon extends Icon {} diff --git a/property-loader/src/main/java/com/github/weisj/darklaf/icons/IconLoader.java b/property-loader/src/main/java/com/github/weisj/darklaf/icons/IconLoader.java index c4f27dcb..1ff6b489 100644 --- a/property-loader/src/main/java/com/github/weisj/darklaf/icons/IconLoader.java +++ b/property-loader/src/main/java/com/github/weisj/darklaf/icons/IconLoader.java @@ -24,6 +24,7 @@ */ package com.github.weisj.darklaf.icons; +import java.awt.*; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -126,6 +127,13 @@ public final class IconLoader { currentThemeKey.set(theme); } + /** + * Reload all created frame icons if necessary. + */ + public static void reloadFrameIcons() { + IconUtil.reloadDynamicFrameIcons(); + } + /** * Get the current aware icon style. * @@ -365,6 +373,19 @@ public final class IconLoader { } } + /** + * Create an {@link Image} from an {@link Icon} suitable for a window icon. + * If the window is moved to a screen with a different scaling factor or + * the theme changes the icon automatically gets updated. + * + * @param icon the icon. + * @param window the window. + * @return the converted {@link Image}. + */ + public static Image createFrameIcon(final Icon icon, final Window window) { + return IconUtil.createFrameIcon(icon, window); + } + protected URL getResource(final String name) { if (parentClass != null) { return parentClass.getResource(name); diff --git a/property-loader/src/main/java/com/github/weisj/darklaf/icons/IconUtil.java b/property-loader/src/main/java/com/github/weisj/darklaf/icons/IconUtil.java new file mode 100644 index 00000000..5b7ad11f --- /dev/null +++ b/property-loader/src/main/java/com/github/weisj/darklaf/icons/IconUtil.java @@ -0,0 +1,110 @@ +/* + * 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.*; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeListener; +import java.util.Map; +import java.util.WeakHashMap; + +import javax.swing.*; + +import com.github.weisj.darklaf.util.ImageUtil; +import com.github.weisj.darklaf.util.PropertyKey; +import com.github.weisj.darklaf.util.Scale; + +public class IconUtil { + + private static final int FRAME_ICON_SIZE = 32; + private static final Map windowIconSet = new WeakHashMap<>(); + + /** + * Reload all created frame icons if necessary. + */ + public static void reloadDynamicFrameIcons() { + SwingUtilities.invokeLater(() -> { + windowIconSet.forEach((window, icon) -> window.setIconImage(iconToImage(icon, window))); + }); + } + + static int getDynamicFrameIconCount() { + return windowIconSet.size(); + } + + public static Image createFrameIcon(final Icon icon, final Window c) { + if (icon == null) return null; + if (c != null) { + if (isDynamic(icon)) { + windowIconSet.put(c, icon); + } + PropertyChangeListener propertyChangeListener = e -> c.setIconImage(iconToImage(icon, c)); + c.addPropertyChangeListener(PropertyKey.GRAPHICS_CONFIGURATION, propertyChangeListener); + } + return createScaledFrameIcon(icon, c); + } + + private static boolean isDynamic(final Icon icon) { + return icon instanceof DynamicIcon; + } + + private static Image createScaledFrameIcon(final Icon icon, final Window c) { + if (c != null && !c.isVisible()) { + Component parent = c.getParent(); + if (parent != null) { + return iconToImage(icon, c); + } + } + return iconToImage(icon, c); + } + + public static Image iconToImage(final Icon icon, final Component c) { + if (icon == null) return null; + int w = icon.getIconWidth(); + int h = icon.getIconHeight(); + GraphicsConfiguration gc = c.getGraphicsConfiguration(); + double sx = Scale.getScaleX(gc); + double sy = Scale.getScaleY(gc); + double scaleX = sx * (((double) FRAME_ICON_SIZE) / w); + double scaleY = sy * (((double) FRAME_ICON_SIZE) / h); + return createScaledImage(icon, scaleX, scaleY); + } + + public static Image createScaledImage(final Icon icon, final double scalex, final double scaley) { + if (icon == null) return null; + int w = (int) (scalex * icon.getIconWidth()); + int h = (int) (scaley * icon.getIconHeight()); + if (icon instanceof ImageSource) { + return ((ImageSource) icon).createImage(w, h); + } else { + BufferedImage image = ImageUtil.createCompatibleTransparentImage(w, h); + Graphics2D g = (Graphics2D) image.getGraphics(); + g.scale(scalex, scaley); + icon.paintIcon(null, g, 0, 0); + g.dispose(); + return image; + } + } +} diff --git a/property-loader/src/main/java/com/github/weisj/darklaf/icons/ThemedIcon.java b/property-loader/src/main/java/com/github/weisj/darklaf/icons/ThemedIcon.java index 42c3416a..d7d07243 100644 --- a/property-loader/src/main/java/com/github/weisj/darklaf/icons/ThemedIcon.java +++ b/property-loader/src/main/java/com/github/weisj/darklaf/icons/ThemedIcon.java @@ -26,4 +26,4 @@ package com.github.weisj.darklaf.icons; import javax.swing.*; -public interface ThemedIcon extends Icon {} +public interface ThemedIcon extends DynamicIcon {} diff --git a/property-loader/src/main/java/com/github/weisj/darklaf/icons/UIAwareIcon.java b/property-loader/src/main/java/com/github/weisj/darklaf/icons/UIAwareIcon.java index a28df0db..d58eb03e 100644 --- a/property-loader/src/main/java/com/github/weisj/darklaf/icons/UIAwareIcon.java +++ b/property-loader/src/main/java/com/github/weisj/darklaf/icons/UIAwareIcon.java @@ -29,7 +29,7 @@ import javax.swing.*; /** * @author Jannis Weis */ -public interface UIAwareIcon extends Icon { +public interface UIAwareIcon extends DynamicIcon { UIAwareIcon getDual(); } diff --git a/property-loader/src/test/java/com/github/weisj/darklaf/icons/IconUtilTest.java b/property-loader/src/test/java/com/github/weisj/darklaf/icons/IconUtilTest.java new file mode 100644 index 00000000..78792443 --- /dev/null +++ b/property-loader/src/test/java/com/github/weisj/darklaf/icons/IconUtilTest.java @@ -0,0 +1,75 @@ +/* + * 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.*; +import java.lang.ref.WeakReference; + +import javax.swing.*; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class IconUtilTest { + + @Test + public void testWeakFrameCache() { + Object obj = new Object(); + WeakReference ref = new WeakReference<>(obj); + int count = 100; + Icon icon = new TestIcon(); + JFrame[] frames = new JFrame[count]; + for (int i = 0; i < count; i++) { + JFrame frame = new JFrame(); + frame.setIconImage(IconUtil.createFrameIcon(icon, frame)); + frames[i] = frame; + } + Assertions.assertEquals(count, IconUtil.getDynamicFrameIconCount()); + for (int i = 0; i < count; i++) { + frames[i].dispose(); + frames[i] = null; + } + while (IconUtil.getDynamicFrameIconCount() != 0) { + System.gc(); + } + Assertions.assertEquals(0, IconUtil.getDynamicFrameIconCount()); + } + + private static class TestIcon implements DynamicIcon { + + @Override + public void paintIcon(final Component c, final Graphics g, final int x, final int y) {} + + @Override + public int getIconWidth() { + return 10; + } + + @Override + public int getIconHeight() { + return 10; + } + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/graphics/ImageUtil.java b/utils/src/main/java/com/github/weisj/darklaf/util/ImageUtil.java similarity index 55% rename from core/src/main/java/com/github/weisj/darklaf/graphics/ImageUtil.java rename to utils/src/main/java/com/github/weisj/darklaf/util/ImageUtil.java index 9a323e89..a3cf7495 100644 --- a/core/src/main/java/com/github/weisj/darklaf/graphics/ImageUtil.java +++ b/utils/src/main/java/com/github/weisj/darklaf/util/ImageUtil.java @@ -22,22 +22,10 @@ * SOFTWARE. * */ -package com.github.weisj.darklaf.graphics; +package com.github.weisj.darklaf.util; import java.awt.*; import java.awt.image.BufferedImage; -import java.beans.PropertyChangeListener; -import java.util.function.BiConsumer; - -import javax.swing.*; - -import com.github.weisj.darklaf.LafManager; -import com.github.weisj.darklaf.icons.ImageSource; -import com.github.weisj.darklaf.icons.ThemedIcon; -import com.github.weisj.darklaf.icons.UIAwareIcon; -import com.github.weisj.darklaf.theme.event.ThemeInstalledListener; -import com.github.weisj.darklaf.util.PropertyKey; -import com.github.weisj.darklaf.util.Scale; /** * @author Jannis Weis @@ -46,99 +34,6 @@ public final class ImageUtil { private ImageUtil() {} - private static final int FRAME_ICON_SIZE = 32; - - public static Image createFrameIcon(final Icon icon, final Window c) { - if (c instanceof JFrame) { - return createFrameIcon(icon, (JFrame) c); - } else if (c instanceof JDialog) { - return createFrameIcon(icon, (JDialog) c); - } else { - return createScaledFrameIcon(icon, c); - } - } - - public static Image createFrameIcon(final Icon icon, final JFrame c) { - return createWindowIcon(icon, c, JFrame::setIconImage); - } - - public static Image createFrameIcon(final Icon icon, final JDialog c) { - return createWindowIcon(icon, c, JDialog::setIconImage); - } - - private static Image createWindowIcon(final Icon icon, final T c, - final BiConsumer iconSetter) { - if (icon == null) return null; - if (c != null) { - if (iconNeedUpdates(icon)) { - ThemeInstalledListener listener = e -> iconSetter.accept(c, iconToImage(icon, c)); - LafManager.addThemeChangeListener(listener); - } - PropertyChangeListener propertyChangeListener = e -> iconSetter.accept(c, iconToImage(icon, c)); - c.addPropertyChangeListener(PropertyKey.GRAPHICS_CONFIGURATION, propertyChangeListener); - } - return createScaledFrameIcon(icon, c); - } - - private static boolean iconNeedUpdates(final Icon icon) { - return icon instanceof UIAwareIcon || icon instanceof ThemedIcon; - } - - private static Image createScaledFrameIcon(final Icon icon, final Window c) { - if (c != null && !c.isVisible()) { - Component parent = c.getParent(); - if (parent != null) { - return iconToImage(icon, c); - } - } - return iconToImage(icon, c); - } - - public static Image iconToImage(final Icon icon, final Component c) { - if (icon == null) return null; - int w = icon.getIconWidth(); - int h = icon.getIconHeight(); - GraphicsConfiguration gc = c.getGraphicsConfiguration(); - double sx = Scale.getScaleX(gc); - double sy = Scale.getScaleY(gc); - double scaleX = sx * (((double) FRAME_ICON_SIZE) / w); - double scaleY = sy * (((double) FRAME_ICON_SIZE) / h); - return createScaledImage(icon, scaleX, scaleY); - } - - public static Image createScaledImage(final Icon icon, final double scalex, final double scaley) { - if (icon == null) return null; - int w = (int) (scalex * icon.getIconWidth()); - int h = (int) (scaley * icon.getIconHeight()); - if (icon instanceof ImageSource) { - return ((ImageSource) icon).createImage(w, h); - } else { - BufferedImage image = createCompatibleTransparentImage(w, h); - Graphics2D g = (Graphics2D) image.getGraphics(); - g.scale(scalex, scaley); - icon.paintIcon(null, g, 0, 0); - g.dispose(); - return image; - } - } - - 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); - } - - public static Image createDragImage(final Component c, final Rectangle bounds, - final int lw, final Color borderColor) { - Image tabImage = ImageUtil.scaledImageFromComponent(c, bounds); - int w = tabImage.getWidth(null); - int h = tabImage.getHeight(null); - Graphics g = tabImage.getGraphics(); - - g.setColor(borderColor); - PaintUtil.drawRect(g, 0, 0, w, h, lw); - g.dispose(); - return tabImage; - } - /** * Create image from component. *