diff --git a/src/dorkbox/notify/AsDialog.java b/src/dorkbox/notify/AsDialog.java index 602493b..9ada5aa 100644 --- a/src/dorkbox/notify/AsDialog.java +++ b/src/dorkbox/notify/AsDialog.java @@ -18,7 +18,6 @@ package dorkbox.notify; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Frame; -import java.awt.Image; import java.awt.Window; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; @@ -43,7 +42,7 @@ class AsDialog extends JDialog implements INotify { // this is on the swing EDT @SuppressWarnings("NumericCastThatLosesPrecision") - AsDialog(final Notify notification, final Image image, final ImageIcon imageIcon, final Window container, final Theme theme) { + AsDialog(final Notify notification, final ImageIcon image, final Window container, final Theme theme) { super(container, Dialog.ModalityType.MODELESS); this.notification = notification; @@ -60,7 +59,7 @@ class AsDialog extends JDialog implements INotify { setTitle(notification.title); setResizable(false); - NotifyCanvas notifyCanvas = new NotifyCanvas(notification, imageIcon, theme); + NotifyCanvas notifyCanvas = new NotifyCanvas(notification, image, theme); add(notifyCanvas); look = new LookAndFeel(this, notifyCanvas, notification, image, container.getBounds()); diff --git a/src/dorkbox/notify/AsFrame.java b/src/dorkbox/notify/AsFrame.java index ba14616..14365a5 100644 --- a/src/dorkbox/notify/AsFrame.java +++ b/src/dorkbox/notify/AsFrame.java @@ -18,7 +18,6 @@ package dorkbox.notify; import java.awt.Dimension; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; -import java.awt.Image; import java.awt.MouseInfo; import java.awt.Point; import java.awt.Rectangle; @@ -42,7 +41,7 @@ class AsFrame extends JFrame implements INotify { // this is on the swing EDT @SuppressWarnings("NumericCastThatLosesPrecision") - AsFrame(final Notify notification, final Image image, final ImageIcon imageIcon, final Theme theme) { + AsFrame(final Notify notification, final ImageIcon image, final Theme theme) { this.notification = notification; setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); @@ -90,7 +89,7 @@ class AsFrame extends JFrame implements INotify { .getBounds(); - NotifyCanvas notifyCanvas = new NotifyCanvas(notification, imageIcon, theme); + NotifyCanvas notifyCanvas = new NotifyCanvas(notification, image, theme); getContentPane().add(notifyCanvas); look = new LookAndFeel(this, notifyCanvas, notification, image, bounds); diff --git a/src/dorkbox/notify/LookAndFeel.java b/src/dorkbox/notify/LookAndFeel.java index 05a6d46..e2b2997 100644 --- a/src/dorkbox/notify/LookAndFeel.java +++ b/src/dorkbox/notify/LookAndFeel.java @@ -15,7 +15,6 @@ */ package dorkbox.notify; -import java.awt.Image; import java.awt.Rectangle; import java.awt.Window; import java.awt.event.MouseAdapter; @@ -25,6 +24,8 @@ import java.util.Iterator; import java.util.Map; import java.util.Random; +import javax.swing.ImageIcon; + import dorkbox.tweenengine.BaseTween; import dorkbox.tweenengine.Tween; import dorkbox.tweenengine.TweenCallback; @@ -91,7 +92,7 @@ class LookAndFeel { LookAndFeel(final Window parent, final NotifyCanvas notifyCanvas, final Notify notification, - final Image image, + final ImageIcon image, final Rectangle parentBounds) { this.parent = parent; @@ -123,7 +124,7 @@ class LookAndFeel { anchorY = getAnchorY(position, parentBounds); if (image != null) { - parent.setIconImage(image); + parent.setIconImage(image.getImage()); } else { parent.setIconImage(SwingUtil.BLANK_ICON); diff --git a/src/dorkbox/notify/Notify.java b/src/dorkbox/notify/Notify.java index 3042a27..9fb63ff 100644 --- a/src/dorkbox/notify/Notify.java +++ b/src/dorkbox/notify/Notify.java @@ -21,6 +21,7 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; @@ -28,6 +29,7 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import dorkbox.util.ActionHandler; +import dorkbox.util.ImageUtil; import dorkbox.util.LocationResolver; import dorkbox.util.Property; import dorkbox.util.SwingUtil; @@ -55,6 +57,12 @@ import dorkbox.util.Version; public final class Notify { + public static final String DIALOG_CONFIRM = "dialog-confirm.png"; + + public static final String DIALOG_INFORMATION = "dialog-information.png"; + public static final String DIALOG_WARNING = "dialog-warning.png"; + public static final String DIALOG_ERROR = "dialog-error.png"; + /** * This is the title font used by a notification. */ @@ -79,8 +87,7 @@ class Notify { @Property public static String IMAGE_PATH = "resources"; - private static Map imageCache = new HashMap(4); - private static Map imageIconCache = new HashMap(4); + private static Map> imageCache = new HashMap>(4); /** * Gets the version number. @@ -98,38 +105,69 @@ class Notify { return new Notify(); } + /** + * Gets the size of the image to be used in the notification, which is a 48x48 pixel image. + */ + public static + int getImageSize() { + return 48; + } + /** * Permits one to override the default images for the dialogs. This is NOT thread safe, and must be performed BEFORE showing a * notification. *

* The image names are as follows: *

- * 'dialog-confirm.png' 'dialog-error.png' 'dialog-information.png' 'dialog-warning.png' + * 'Notify.DIALOG_CONFIRM' 'Notify.DIALOG_INFORMATION' 'Notify.DIALOG_WARNING' 'Notify.DIALOG_ERROR' * * @param imageName the name of the image, either your own if you want want it cached, or one of the above. * @param image the BufferedImage that you want to cache. */ public static - void setImagePath(String imageName, BufferedImage image) { + void overrideDefaultImage(String imageName, BufferedImage image) { if (imageCache.containsKey(imageName)) { throw new RuntimeException("Unable to set an image that already has been set. This action must be done as soon as possible."); } - imageCache.put(imageName, image); + Image imageImmediate = ImageUtil.getImageImmediate(image); + + // we only use 48x48 pixel images. Resize as necessary + int width = imageImmediate.getWidth(null); + int height = imageImmediate.getHeight(null); + + BufferedImage bufferedImage; + + // resize the image, keep aspect ratio + if (width > height) { + bufferedImage = ImageUtil.resizeImage(image, getImageSize(), -1); + } + else { + bufferedImage = ImageUtil.resizeImage(image, -1, getImageSize()); + } + + imageCache.put(imageName, new SoftReference(new ImageIcon(bufferedImage))); } private static - BufferedImage getImage(String imageName) { - BufferedImage bufferedImage = imageCache.get(imageName); + ImageIcon getImage(String imageName) { + ImageIcon image = null; InputStream resourceAsStream = null; + try { - if (bufferedImage == null) { + SoftReference reference = imageCache.get(imageName); + + if (reference != null) { + image = reference.get(); + } + + if (image == null) { String name = IMAGE_PATH + File.separatorChar + imageName; resourceAsStream = LocationResolver.getResourceAsStream(name); - bufferedImage = ImageIO.read(resourceAsStream); - imageCache.put(imageName, bufferedImage); + image = new ImageIcon(ImageUtil.getImageImmediate(ImageIO.read(resourceAsStream))); + imageCache.put(imageName, new SoftReference(image)); } } catch (IOException e) { e.printStackTrace(); @@ -143,7 +181,7 @@ class Notify { } } - return bufferedImage; + return image; } @@ -158,7 +196,7 @@ class Notify { boolean hideCloseButton; boolean isDark = false; int screenNumber = Short.MIN_VALUE; - private Image graphic; + private ImageIcon icon; ActionHandler onCloseAction; private INotify notifyPopup; @@ -191,11 +229,24 @@ class Notify { } /** - * Specifies the graphic + * Specifies the image */ public - Notify graphic(Image graphic) { - this.graphic = graphic; + Notify image(Image image) { + // we only use 48x48 pixel images. Resize as necessary + int width = image.getWidth(null); + int height = image.getHeight(null); + + BufferedImage bufferedImage = ImageUtil.getBufferedImage(image); + + // resize the image, keep aspect ratio + if (width > height) { + bufferedImage = ImageUtil.resizeImage(bufferedImage, 48, -1); + } else { + bufferedImage = ImageUtil.resizeImage(bufferedImage, -1, 48); + } + + this.icon = new ImageIcon(bufferedImage); return this; } @@ -259,47 +310,48 @@ class Notify { } /** - * Shows the notification with the built-in 'warning' graphic. + * Shows the notification with the built-in 'warning' image. */ public void showWarning() { - name = "dialog-warning.png"; - graphic(getImage(name)); + name = DIALOG_WARNING; + icon = getImage(name); show(); } /** - * Shows the notification with the built-in 'information' graphic. + * Shows the notification with the built-in 'information' image. */ public void showInformation() { - name = "dialog-information.png"; - graphic(getImage(name)); + name = DIALOG_INFORMATION; + icon = getImage(name); show(); } /** - * Shows the notification with the built-in 'error' graphic. + * Shows the notification with the built-in 'error' image. */ public void showError() { - name = "dialog-error.png"; - graphic(getImage(name)); + name = DIALOG_ERROR; + icon = getImage(name); show(); } /** - * Shows the notification with the built-in 'confirm' graphic. + * Shows the notification with the built-in 'confirm' image. */ public void showConfirm() { - name = "dialog-confirm.png"; - graphic(getImage(name)); + name = DIALOG_CONFIRM; + icon = getImage(name); show(); } /** - * Shows the notification. If the Notification is assigned to a screen, but shown in a JFrame, the screen number will be ignored. + * Shows the notification. If the Notification is assigned to a screen, but shown inside a Swing/etc parent, the screen number will be + * ignored. */ public void show() { @@ -310,26 +362,7 @@ class Notify { public void run() { final Notify notify = Notify.this; - final Image graphic = notify.graphic; - - // we ONLY cache our own icons - ImageIcon imageIcon = null; - if (graphic != null) { - if (name != null) { - imageIcon = imageIconCache.get(name); - if (imageIcon == null) { - Image image = new ImageIcon(graphic).getImage(); - - // have to do this twice, so that it will finish loading the image (weird callback stuff is required if we don't do this) - imageIcon = new ImageIcon(image); - - imageIconCache.put(name, imageIcon); - } - } - else { - imageIcon = new ImageIcon(graphic); - } - } + final ImageIcon image = notify.icon; Theme theme; if (notify.theme != null) { @@ -340,9 +373,9 @@ class Notify { } if (window == null) { - notifyPopup = new AsFrame(notify, graphic, imageIcon, theme); + notifyPopup = new AsFrame(notify, image, theme); } else { - notifyPopup = new AsDialog(notify, graphic, imageIcon, window, theme); + notifyPopup = new AsDialog(notify, image, window, theme); } notifyPopup.setVisible(true); @@ -354,7 +387,7 @@ class Notify { }); // don't need to hang onto these. - graphic = null; + icon = null; } /** diff --git a/test/NotifyTest.java b/test/NotifyTest.java index 421c104..8aae55b 100644 --- a/test/NotifyTest.java +++ b/test/NotifyTest.java @@ -126,7 +126,7 @@ class NotifyTest { .hideAfter(13000) .position(Pos.BOTTOM_LEFT) // .setScreen(0) - .darkStyle() +// .darkStyle() // .shake(1300, 4) // .shake(1300, 10) .hideCloseButton()