package envoy.client.util; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.*; import java.util.logging.Level; import javax.imageio.ImageIO; import javafx.scene.image.Image; import envoy.util.EnvoyLog; import envoy.client.data.Settings; /** * Provides static utility methods for loading icons from the resource folder. * * @author Kai S. K. Engelbart * @since Envoy Client v0.1-beta */ public final class IconUtil { private static final HashMap cache = new HashMap<>(); private static final HashMap scaledCache = new HashMap<>(); private static final HashMap awtCache = new HashMap<>(); private IconUtil() {} /** * Loads an image from the resource folder. * * @param path the path to the icon inside the resource folder * @return the loaded image * @since Envoy Client v0.1-beta */ public static Image load(String path) { return cache.computeIfAbsent(path, p -> new Image(IconUtil.class.getResource(p).toExternalForm())); } /** * Loads an image from the resource folder and scales it to the given size. * * @param path the path to the icon inside the resource folder * @param size the size to scale the icon to * @return the scaled image * @since Envoy Client v0.1-beta */ public static Image load(String path, int size) { return scaledCache.computeIfAbsent(path + size, p -> new Image(IconUtil.class.getResource(path).toExternalForm(), size, size, true, true)); } /** * Loads a {@code .png} image from the sub-folder {@code /icons/} of the resource folder. *

* The suffix {@code .png} is automatically appended. * * @param name the image name without the .png suffix * @return the loaded image * @since Envoy Client v0.1-beta * @apiNote let's load a sample image {@code /icons/abc.png}.
* To do that, we only have to call {@code IconUtil.loadIcon("abc")} */ public static Image loadIcon(String name) { return load("/icons/" + name + ".png"); } /** * Loads a {@code .png} image from the sub-folder {@code /icons/} of the resource folder and * scales it to the given size.
* The suffix {@code .png} is automatically appended. * * @param name the image name without the .png suffix * @param size the size of the image to scale to * @return the loaded image * @since Envoy Client v0.1-beta * @apiNote let's load a sample image {@code /icons/abc.png} in size 16.
* To do that, we only have to call {@code IconUtil.loadIcon("abc", 16)} */ public static Image loadIcon(String name, int size) { return load("/icons/" + name + ".png", size); } /** * Loads a {@code .png} image whose design depends on the currently active theme from the * sub-folder {@code /icons/dark/} or {@code /icons/light/} of the resource folder. *

* The suffix {@code .png} is automatically appended. * * @param name the image name without the "black" or "white" suffix and without the .png suffix * @return the loaded image * @since Envoy Client v0.1-beta * @apiNote let's take two sample images {@code /icons/dark/abc.png} and * {@code /icons/light/abc.png}, and load one of them.
* To do that theme sensitive, we only have to call * {@code IconUtil.loadIconThemeSensitive("abc")} */ public static Image loadIconThemeSensitive(String name) { return loadIcon(themeSpecificSubFolder() + name); } /** * Loads a {@code .png} image whose design depends on the currently active theme from the * sub-folder {@code /icons/dark/} or {@code /icons/light/} of the resource folder and scales it * to the given size. *

* The suffix {@code .png} is automatically appended. * * @param name the image name without the .png suffix * @param size the size of the image to scale to * @return the loaded image * @since Envoy Client v0.1-beta * @apiNote let's take two sample images {@code /icons/dark/abc.png} and * {@code /icons/light/abc.png}, and load one of them in size 16.
* To do that theme sensitive, we only have to call * {@code IconUtil.loadIconThemeSensitive("abc", 16)} */ public static Image loadIconThemeSensitive(String name, int size) { return loadIcon(themeSpecificSubFolder() + name, size); } /** * Loads images specified by an enum. The images have to be named like the lowercase enum * constants with {@code .png} extension and be located inside a folder with the lowercase name * of the enum, which must be contained inside the {@code /icons/} folder. * * @param the enum that specifies the images to load * @param enumClass the class of the enum * @param size the size to scale the images to * @return a map containing the loaded images with the corresponding enum constants as keys * @since Envoy Client v0.1-beta */ public static > EnumMap loadByEnum(Class enumClass, int size) { final var icons = new EnumMap(enumClass); final var path = "/icons/" + enumClass.getSimpleName().toLowerCase() + "/"; for (final var e : EnumSet.allOf(enumClass)) icons.put(e, load(path + e.toString().toLowerCase() + ".png", size)); return icons; } /** * Loads a buffered image from the resource folder which is compatible with AWT. * * @param path the path to the icon inside the resource folder * @return the loaded image * @since Envoy Client v0.2-beta */ public static BufferedImage loadAWTCompatible(String path) { return awtCache.computeIfAbsent(path, p -> { try { return ImageIO.read(IconUtil.class.getResource(path)); } catch (IOException e) { EnvoyLog.getLogger(IconUtil.class).log(Level.WARNING, String.format("Could not load image at path %s: ", path), e); return null; } }); } /** * This method should be called if the display of an image depends upon the currently active * theme.
* In case of a default theme, the string returned will be ({@code dark/} or {@code light/}), * otherwise it will be empty. * * @return the theme specific folder * @since Envoy Client v0.1-beta */ private static String themeSpecificSubFolder() { return Settings.getInstance().isUsingDefaultTheme() ? Settings.getInstance().getCurrentTheme() + "/" : ""; } }