|
|
@ -35,12 +35,16 @@ import java.util.logging.Logger; |
|
|
|
|
|
|
|
|
|
|
|
import javax.swing.*; |
|
|
|
import javax.swing.*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import org.jetbrains.annotations.Contract; |
|
|
|
|
|
|
|
import org.jetbrains.annotations.NotNull; |
|
|
|
|
|
|
|
import org.jetbrains.annotations.Nullable; |
|
|
|
|
|
|
|
|
|
|
|
import com.github.weisj.darklaf.util.LazyValue; |
|
|
|
import com.github.weisj.darklaf.util.LazyValue; |
|
|
|
import com.github.weisj.darklaf.util.LogUtil; |
|
|
|
import com.github.weisj.darklaf.util.LogUtil; |
|
|
|
import com.github.weisj.darklaf.util.cache.SoftCache; |
|
|
|
import com.github.weisj.darklaf.util.cache.SoftCache; |
|
|
|
|
|
|
|
|
|
|
|
/** @author Jannis Weis */ |
|
|
|
/** @author Jannis Weis */ |
|
|
|
public final class IconLoader { |
|
|
|
public final class IconLoader implements IconResolver { |
|
|
|
private static final Logger LOGGER = LogUtil.getLogger(IconLoader.class); |
|
|
|
private static final Logger LOGGER = LogUtil.getLogger(IconLoader.class); |
|
|
|
private static final Map<Class<?>, IconLoader> iconLoaderMap = new HashMap<>(); |
|
|
|
private static final Map<Class<?>, IconLoader> iconLoaderMap = new HashMap<>(); |
|
|
|
private static final LazyValue<IconLoader> instance = new LazyValue<>(() -> get(null)); |
|
|
|
private static final LazyValue<IconLoader> instance = new LazyValue<>(() -> get(null)); |
|
|
@ -51,7 +55,7 @@ public final class IconLoader { |
|
|
|
// Infer size by default.
|
|
|
|
// Infer size by default.
|
|
|
|
private static final int DEFAULT_WIDTH_SVG = -1; |
|
|
|
private static final int DEFAULT_WIDTH_SVG = -1; |
|
|
|
private static final int DEFAULT_HEIGHT_SVG = -1; |
|
|
|
private static final int DEFAULT_HEIGHT_SVG = -1; |
|
|
|
private final Class<?> parentClass; |
|
|
|
private final @Nullable Class<?> parentClass; |
|
|
|
|
|
|
|
|
|
|
|
private boolean cacheEnabled = true; |
|
|
|
private boolean cacheEnabled = true; |
|
|
|
private final SoftCache<IconKey, DarkUIAwareIcon> awareIconCache = new SoftCache<>(); |
|
|
|
private final SoftCache<IconKey, DarkUIAwareIcon> awareIconCache = new SoftCache<>(); |
|
|
@ -85,7 +89,7 @@ public final class IconLoader { |
|
|
|
return awareIconCache.isEmpty() && iconCache.isEmpty(); |
|
|
|
return awareIconCache.isEmpty() && iconCache.isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private IconLoader(final Class<?> parentClass) { |
|
|
|
private IconLoader(final @Nullable Class<?> parentClass) { |
|
|
|
this.parentClass = parentClass; |
|
|
|
this.parentClass = parentClass; |
|
|
|
iconLoaderMap.put(parentClass, this); |
|
|
|
iconLoaderMap.put(parentClass, this); |
|
|
|
} |
|
|
|
} |
|
|
@ -95,7 +99,7 @@ public final class IconLoader { |
|
|
|
* |
|
|
|
* |
|
|
|
* @return the default icon loader. |
|
|
|
* @return the default icon loader. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static IconLoader get() { |
|
|
|
public static @NotNull IconLoader get() { |
|
|
|
return instance.get(); |
|
|
|
return instance.get(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -104,7 +108,7 @@ public final class IconLoader { |
|
|
|
* |
|
|
|
* |
|
|
|
* @return the default icon loader. |
|
|
|
* @return the default icon loader. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static IconLoader get(final Class<?> parentClass) { |
|
|
|
public static @NotNull IconLoader get(final @Nullable Class<?> parentClass) { |
|
|
|
if (iconLoaderMap.containsKey(parentClass)) { |
|
|
|
if (iconLoaderMap.containsKey(parentClass)) { |
|
|
|
return iconLoaderMap.get(parentClass); |
|
|
|
return iconLoaderMap.get(parentClass); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -195,10 +199,31 @@ public final class IconLoader { |
|
|
|
* @param path the path to the icon resource described as above. |
|
|
|
* @param path the path to the icon resource described as above. |
|
|
|
* @return the icon. |
|
|
|
* @return the icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public DarkUIAwareIcon getUIAwareIcon(final String path) { |
|
|
|
@Override |
|
|
|
|
|
|
|
public @NotNull DarkUIAwareIcon getUIAwareIcon(final @NotNull String path) { |
|
|
|
return getUIAwareIcon(path, getDefaultWidth(path), getDefaultHeight(path)); |
|
|
|
return getUIAwareIcon(path, getDefaultWidth(path), getDefaultHeight(path)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Get an aware icon. If [path] is the search root of the current icon loader then the icon resource |
|
|
|
|
|
|
|
* will be resolved to [path]/dark/[icon_path] and [path]/light/[icon_path] |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param path the path to the icon resource described as above. |
|
|
|
|
|
|
|
* @param w the icon width. |
|
|
|
|
|
|
|
* @param h the icon height. |
|
|
|
|
|
|
|
* @return the icon. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public @NotNull DarkUIAwareIcon getUIAwareIcon(final @NotNull String path, final int w, final int h) { |
|
|
|
|
|
|
|
IconKey key = new IconKey(path, w, h); |
|
|
|
|
|
|
|
DarkUIAwareIcon icon; |
|
|
|
|
|
|
|
if (!isCacheEnabled() || ((icon = awareIconCache.get(key)) == null)) { |
|
|
|
|
|
|
|
icon = createUIAwareIcon(path, w, h); |
|
|
|
|
|
|
|
cache(awareIconCache, key, icon); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return icon; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Creates a new {@link UIAwareIcon} which is loaded lazily through the given supplier. |
|
|
|
* Creates a new {@link UIAwareIcon} which is loaded lazily through the given supplier. |
|
|
|
* |
|
|
|
* |
|
|
@ -206,7 +231,7 @@ public final class IconLoader { |
|
|
|
* @param darkIconSupplier the supplier for the dark icon. |
|
|
|
* @param darkIconSupplier the supplier for the dark icon. |
|
|
|
* @return the {@link UIAwareIcon} |
|
|
|
* @return the {@link UIAwareIcon} |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public UIAwareIcon createUIAwareIcon(final IconSupplier<Icon> lightIconSupplier, |
|
|
|
public @NotNull UIAwareIcon createUIAwareIcon(final IconSupplier<Icon> lightIconSupplier, |
|
|
|
final IconSupplier<Icon> darkIconSupplier) { |
|
|
|
final IconSupplier<Icon> darkIconSupplier) { |
|
|
|
return new LazyUIAwareIcon(lightIconSupplier, darkIconSupplier); |
|
|
|
return new LazyUIAwareIcon(lightIconSupplier, darkIconSupplier); |
|
|
|
} |
|
|
|
} |
|
|
@ -218,33 +243,14 @@ public final class IconLoader { |
|
|
|
* @param dark the dark version of the icon. |
|
|
|
* @param dark the dark version of the icon. |
|
|
|
* @return the {@link UIAwareIcon}. |
|
|
|
* @return the {@link UIAwareIcon}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public UIAwareIcon createUIAwareIcon(final Icon light, final Icon dark) { |
|
|
|
public @NotNull UIAwareIcon createUIAwareIcon(final Icon light, final Icon dark) { |
|
|
|
return new SimpleUIAwareIcon(light, dark); |
|
|
|
return new SimpleUIAwareIcon(light, dark); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Get an aware icon. If [path] is the search root of the current icon loader then the icon resource |
|
|
|
|
|
|
|
* will be resolved to [path]/dark/[icon_path] and [path]/light/[icon_path] |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* @param path the path to the icon resource described as above. |
|
|
|
|
|
|
|
* @param w the icon width. |
|
|
|
|
|
|
|
* @param h the icon height. |
|
|
|
|
|
|
|
* @return the icon. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public DarkUIAwareIcon getUIAwareIcon(final String path, final int w, final int h) { |
|
|
|
|
|
|
|
IconKey key = new IconKey(path, w, h); |
|
|
|
|
|
|
|
DarkUIAwareIcon icon; |
|
|
|
|
|
|
|
if (!isCacheEnabled() || ((icon = awareIconCache.get(key)) == null)) { |
|
|
|
|
|
|
|
icon = createUIAwareIcon(path, w, h); |
|
|
|
|
|
|
|
cache(awareIconCache, key, icon); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return icon; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
/* |
|
|
|
* Helper method to create the icons. |
|
|
|
* Helper method to create the icons. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected DarkUIAwareIcon createUIAwareIcon(final String name, final int w, final int h) { |
|
|
|
protected @NotNull DarkUIAwareIcon createUIAwareIcon(final @NotNull String name, final int w, final int h) { |
|
|
|
return new DarkUIAwareIcon("dark/" + name, "light/" + name, w, h, parentClass); |
|
|
|
return new DarkUIAwareIcon("dark/" + name, "light/" + name, w, h, parentClass); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -257,7 +263,8 @@ public final class IconLoader { |
|
|
|
* @param path the path to the icon with respect to the IconLoader resource root. |
|
|
|
* @param path the path to the icon with respect to the IconLoader resource root. |
|
|
|
* @return the icon. |
|
|
|
* @return the icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Icon getIcon(final String path) { |
|
|
|
@Override |
|
|
|
|
|
|
|
public @NotNull Icon getIcon(final @NotNull String path) { |
|
|
|
return getIcon(path, getDefaultWidth(path), getDefaultHeight(path)); |
|
|
|
return getIcon(path, getDefaultWidth(path), getDefaultHeight(path)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -271,7 +278,8 @@ public final class IconLoader { |
|
|
|
* @param themed determines whether the icon is themed. This only has an effect on svg icons. |
|
|
|
* @param themed determines whether the icon is themed. This only has an effect on svg icons. |
|
|
|
* @return the icon. |
|
|
|
* @return the icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Icon getIcon(final String path, final boolean themed) { |
|
|
|
@Override |
|
|
|
|
|
|
|
public @NotNull Icon getIcon(final @NotNull String path, final boolean themed) { |
|
|
|
return getIcon(path, getDefaultWidth(path), getDefaultHeight(path), themed); |
|
|
|
return getIcon(path, getDefaultWidth(path), getDefaultHeight(path), themed); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -286,7 +294,8 @@ public final class IconLoader { |
|
|
|
* @param h the icon height. |
|
|
|
* @param h the icon height. |
|
|
|
* @return the icon. |
|
|
|
* @return the icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Icon getIcon(final String path, final int w, final int h) { |
|
|
|
@Override |
|
|
|
|
|
|
|
public @NotNull Icon getIcon(final @NotNull String path, final int w, final int h) { |
|
|
|
return getIcon(path, w, h, false); |
|
|
|
return getIcon(path, w, h, false); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -302,11 +311,13 @@ public final class IconLoader { |
|
|
|
* @param themed determines whether the icon is themed. This only has an effect on svg icons. |
|
|
|
* @param themed determines whether the icon is themed. This only has an effect on svg icons. |
|
|
|
* @return the icon. |
|
|
|
* @return the icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Icon getIcon(final String path, final int w, final int h, final boolean themed) { |
|
|
|
@Override |
|
|
|
|
|
|
|
public @NotNull Icon getIcon(final @NotNull String path, final int w, final int h, final boolean themed) { |
|
|
|
return getIconImpl(path, w, h, themed); |
|
|
|
return getIconImpl(path, w, h, themed); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Icon getIconImpl(final String path, final int w, final int h, final boolean themed) { |
|
|
|
@NotNull |
|
|
|
|
|
|
|
private Icon getIconImpl(final @NotNull String path, final int w, final int h, final boolean themed) { |
|
|
|
synchronized (this) { |
|
|
|
synchronized (this) { |
|
|
|
IconKey key = new IconKey(path, w, h); |
|
|
|
IconKey key = new IconKey(path, w, h); |
|
|
|
|
|
|
|
|
|
|
@ -330,7 +341,7 @@ public final class IconLoader { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private CacheableIcon getWildcardIcon(final SoftCache<IconKey, CacheableIcon> iconMap, |
|
|
|
private @Nullable CacheableIcon getWildcardIcon(final SoftCache<IconKey, CacheableIcon> iconMap, |
|
|
|
final IconKey iconKey, final int w, final int h) { |
|
|
|
final IconKey iconKey, final int w, final int h) { |
|
|
|
iconKey.isWildcardEnabled = true; |
|
|
|
iconKey.isWildcardEnabled = true; |
|
|
|
CacheableIcon icon = iconMap.get(iconKey); |
|
|
|
CacheableIcon icon = iconMap.get(iconKey); |
|
|
@ -361,7 +372,7 @@ public final class IconLoader { |
|
|
|
* @param themed determines whether the icon is themed. This only has an effect on svg icons. |
|
|
|
* @param themed determines whether the icon is themed. This only has an effect on svg icons. |
|
|
|
* @return the icon. |
|
|
|
* @return the icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Icon loadSVGIcon(final String path, final boolean themed) { |
|
|
|
public @NotNull Icon loadSVGIcon(final @NotNull String path, final boolean themed) { |
|
|
|
return loadSVGIcon(path, DEFAULT_WIDTH_SVG, DEFAULT_HEIGHT_SVG, themed); |
|
|
|
return loadSVGIcon(path, DEFAULT_WIDTH_SVG, DEFAULT_HEIGHT_SVG, themed); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -376,7 +387,7 @@ public final class IconLoader { |
|
|
|
* @param themed determines whether the icon is themed. This only has an effect on svg icons. |
|
|
|
* @param themed determines whether the icon is themed. This only has an effect on svg icons. |
|
|
|
* @return the icon. |
|
|
|
* @return the icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Icon loadSVGIcon(final String path, final int w, final int h, final boolean themed) { |
|
|
|
public @NotNull Icon loadSVGIcon(final @NotNull String path, final int w, final int h, final boolean themed) { |
|
|
|
return loadSVGIcon(path, w, h, themed, null); |
|
|
|
return loadSVGIcon(path, w, h, themed, null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -393,7 +404,7 @@ public final class IconLoader { |
|
|
|
* will be used. |
|
|
|
* will be used. |
|
|
|
* @return the icon. |
|
|
|
* @return the icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Icon loadSVGIcon(final String path, final int w, final int h, final boolean themed, |
|
|
|
public @NotNull Icon loadSVGIcon(final @NotNull String path, final int w, final int h, final boolean themed, |
|
|
|
final Map<Object, Object> propertyMap) { |
|
|
|
final Map<Object, Object> propertyMap) { |
|
|
|
return loadSVGIconInternal(path, w, h, themed, propertyMap); |
|
|
|
return loadSVGIconInternal(path, w, h, themed, propertyMap); |
|
|
|
} |
|
|
|
} |
|
|
@ -439,7 +450,8 @@ public final class IconLoader { |
|
|
|
* {@link ImageIcon#setDescription(String)} |
|
|
|
* {@link ImageIcon#setDescription(String)} |
|
|
|
* @return the ImageIcon. |
|
|
|
* @return the ImageIcon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
ImageIcon createImageIcon(final String path, final String description) { |
|
|
|
@Nullable |
|
|
|
|
|
|
|
ImageIcon createImageIcon(final @NotNull String path, final String description) { |
|
|
|
URL imgURL = getResource(path); |
|
|
|
URL imgURL = getResource(path); |
|
|
|
if (imgURL != null) { |
|
|
|
if (imgURL != null) { |
|
|
|
return new ImageIcon(imgURL, description); |
|
|
|
return new ImageIcon(imgURL, description); |
|
|
@ -458,7 +470,8 @@ public final class IconLoader { |
|
|
|
* @param window the window. |
|
|
|
* @param window the window. |
|
|
|
* @return the converted {@link Image}. |
|
|
|
* @return the converted {@link Image}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static Image createFrameIcon(final Icon icon, final Window window) { |
|
|
|
@Contract("null,_ -> null") |
|
|
|
|
|
|
|
public static Image createFrameIcon(final @Nullable Icon icon, final Window window) { |
|
|
|
return IconUtil.createFrameIcon(icon, window); |
|
|
|
return IconUtil.createFrameIcon(icon, window); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -472,11 +485,11 @@ public final class IconLoader { |
|
|
|
* @param h the new height. |
|
|
|
* @param h the new height. |
|
|
|
* @return the derived icon. |
|
|
|
* @return the derived icon. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static Icon createDerivedIcon(final Icon icon, final int w, final int h) { |
|
|
|
public static @NotNull Icon createDerivedIcon(final @NotNull Icon icon, final int w, final int h) { |
|
|
|
return IconUtil.createDerivedIcon(icon, w, h); |
|
|
|
return IconUtil.createDerivedIcon(icon, w, h); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected URL getResource(final String name) { |
|
|
|
private URL getResource(final String name) { |
|
|
|
if (parentClass != null) { |
|
|
|
if (parentClass != null) { |
|
|
|
return parentClass.getResource(name); |
|
|
|
return parentClass.getResource(name); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -501,7 +514,7 @@ public final class IconLoader { |
|
|
|
public interface CacheableIcon extends Icon, SoftCache.Cacheable<IconKey> { |
|
|
|
public interface CacheableIcon extends Icon, SoftCache.Cacheable<IconKey> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected static final class IconKey { |
|
|
|
static final class IconKey { |
|
|
|
final String path; |
|
|
|
final String path; |
|
|
|
int w; |
|
|
|
int w; |
|
|
|
int h; |
|
|
|
int h; |
|
|
@ -526,7 +539,7 @@ public final class IconLoader { |
|
|
|
IconKey iconKey = (IconKey) o; |
|
|
|
IconKey iconKey = (IconKey) o; |
|
|
|
|
|
|
|
|
|
|
|
if (iconKey.isWildcardEnabled || this.isWildcardEnabled) { |
|
|
|
if (iconKey.isWildcardEnabled || this.isWildcardEnabled) { |
|
|
|
// Math any size.
|
|
|
|
// Match any size.
|
|
|
|
return Objects.equals(path, iconKey.path); |
|
|
|
return Objects.equals(path, iconKey.path); |
|
|
|
} |
|
|
|
} |
|
|
|
if (w != iconKey.w) return false; |
|
|
|
if (w != iconKey.w) return false; |
|
|
|