diff --git a/core/src/main/java/com/github/weisj/darklaf/DarkLaf.java b/core/src/main/java/com/github/weisj/darklaf/DarkLaf.java index 33e034ea..21a408ea 100644 --- a/core/src/main/java/com/github/weisj/darklaf/DarkLaf.java +++ b/core/src/main/java/com/github/weisj/darklaf/DarkLaf.java @@ -25,6 +25,7 @@ package com.github.weisj.darklaf; import com.github.weisj.darklaf.components.border.DarkBorders; import com.github.weisj.darklaf.platform.Decorations; +import com.github.weisj.darklaf.theme.FontSizeRule; import com.github.weisj.darklaf.theme.Theme; import com.github.weisj.darklaf.ui.DarkPopupFactory; import com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuUI; @@ -104,9 +105,10 @@ public class DarkLaf extends BasicLookAndFeel { public UIDefaults getDefaults() { final UIDefaults metalDefaults = new MetalLookAndFeel().getDefaults(); final UIDefaults defaults = base.getDefaults(); + final Theme currentTheme = LafManager.getTheme(); try { initInputMapDefaults(defaults); - loadThemeDefaults(defaults); + loadThemeDefaults(currentTheme, defaults); setupUtils(defaults); initIdeaDefaults(defaults); @@ -114,6 +116,7 @@ public class DarkLaf extends BasicLookAndFeel { if (SystemInfo.isMac) { patchMacOSFonts(defaults); } + applyFontRule(currentTheme, defaults); setupDecorations(); String key = DarkPopupMenuUI.KEY_DEFAULT_LIGHTWEIGHT_POPUPS; @@ -132,6 +135,26 @@ public class DarkLaf extends BasicLookAndFeel { return defaults; } + private void applyFontRule(final Theme currentTheme, final UIDefaults defaults) { + FontSizeRule rule = currentTheme.getFontSizeRule(); + if (rule == null || rule == FontSizeRule.DEFAULT) return; + for (Map.Entry entry : defaults.entrySet()) { + if (entry != null && entry.getValue() instanceof Font) { + entry.setValue(fontWithRule((Font) entry.getValue(), currentTheme, rule, defaults)); + } + } + } + + private Font fontWithRule(final Font font, final Theme currentTheme, + final FontSizeRule rule, final UIDefaults defaults) { + Font withRule = currentTheme.getFontMapper(rule).map(font, defaults); + if (font instanceof UIResource + && !(withRule instanceof UIResource)) { + withRule = new FontUIResource(withRule); + } + return withRule; + } + private void setupUtils(final UIDefaults defaults) { DarkUIUtil.setDropOpacity(defaults.getInt("dropOpacity") / 100f); DarkUIUtil.setGlowOpacity(defaults.getInt("glowOpacity") / 100f); @@ -222,9 +245,8 @@ public class DarkLaf extends BasicLookAndFeel { } } - private void loadThemeDefaults(final UIDefaults defaults) { + private void loadThemeDefaults(final Theme currentTheme, final UIDefaults defaults) { Properties uiProps = new Properties(); - final Theme currentTheme = LafManager.getTheme(); currentTheme.loadDefaults(uiProps, defaults); //Load overwrites the user has set. PropertyLoader.putProperties(LafManager.getUserProperties(), uiProps, defaults); @@ -245,6 +267,8 @@ public class DarkLaf extends BasicLookAndFeel { } private void loadFontProperties(final Properties uiProps, final UIDefaults defaults) { + Properties fontSizeProps = PropertyLoader.loadProperties(DarkLaf.class, "font_sizes", "properties/"); + PropertyLoader.putProperties(fontSizeProps, uiProps, defaults); Properties fontProps = PropertyLoader.loadProperties(DarkLaf.class, "font", "properties/"); PropertyLoader.putProperties(fontProps, uiProps, defaults); } diff --git a/core/src/main/java/com/github/weisj/darklaf/LafManager.java b/core/src/main/java/com/github/weisj/darklaf/LafManager.java index 8b43da2b..23b3f168 100644 --- a/core/src/main/java/com/github/weisj/darklaf/LafManager.java +++ b/core/src/main/java/com/github/weisj/darklaf/LafManager.java @@ -25,9 +25,7 @@ package com.github.weisj.darklaf; import com.github.weisj.darklaf.icons.AwareIconStyle; import com.github.weisj.darklaf.icons.IconLoader; -import com.github.weisj.darklaf.theme.DarculaTheme; -import com.github.weisj.darklaf.theme.IntelliJTheme; -import com.github.weisj.darklaf.theme.Theme; +import com.github.weisj.darklaf.theme.*; import javax.swing.*; import java.awt.*; @@ -46,6 +44,7 @@ import java.util.logging.Logger; */ public final class LafManager { + private static ThemeProvider themeProvider; private static Theme theme; private static boolean logEnabled = false; private static boolean decorationsOverwrite = true; @@ -91,7 +90,7 @@ public final class LafManager { } /** - * Set globally whether decorations are enabled. By default this is true. Decorations are used if this value is set + * Set globally whether decorations are enabled. By default, this is true. Decorations are used if this value is set * to true and the current platform and theme support custom decorations. * * @param enabled true if decorations should be used if available. @@ -105,6 +104,29 @@ public final class LafManager { } } + public static ThemeProvider getThemeProvider() { + if (themeProvider == null) themeProvider = createDefaultThemeProvider(); + return themeProvider; + } + + public static void setThemeProvider(final ThemeProvider themeProvider) { + LafManager.themeProvider = themeProvider; + } + + private static ThemeProvider createDefaultThemeProvider() { + return new DefaultThemeProvider(); + } + + /** + * Get the associated theme for the given preferred style. + * + * @param style the preferred theme style. + * @return the associated Theme or best match if there is none associated. + */ + public static Theme themeForPreferredStyle(final PreferredThemeStyle style) { + return getThemeProvider().getTheme(style); + } + /** * Get the current theme. This method will never return null even if the LaF isn#t currently installed. * @@ -112,7 +134,7 @@ public final class LafManager { */ public static Theme getTheme() { if (theme == null) { - setTheme(new IntelliJTheme()); + setTheme(themeForPreferredStyle(null)); } return theme; } @@ -124,11 +146,30 @@ public final class LafManager { */ public static void setTheme(final Theme theme) { LafManager.theme = theme; - IconLoader.updateAwareStyle(theme.isDark() ? AwareIconStyle.DARK - : AwareIconStyle.LIGHT); + IconLoader.updateAwareStyle(Theme.isDark(theme) ? AwareIconStyle.DARK + : AwareIconStyle.LIGHT); IconLoader.updateThemeStatus(theme); } + /** + * Install the theme suited for the given preferred theme style. + * + * @param preferredThemeStyle the preferred theme style. + */ + public static void installTheme(final PreferredThemeStyle preferredThemeStyle) { + setTheme(preferredThemeStyle); + install(); + } + + /** + * Sets the theme suited for the given preferred theme style. + * + * @param preferredThemeStyle the preferred theme style. + */ + public static void setTheme(final PreferredThemeStyle preferredThemeStyle) { + setTheme(themeForPreferredStyle(preferredThemeStyle)); + } + /** * Sets the current theme and installs the LaF. If the LaF is already installed the theme is switched. This behaves diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/ContrastRule.java b/core/src/main/java/com/github/weisj/darklaf/theme/ContrastRule.java new file mode 100644 index 00000000..0e022ecb --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/ContrastRule.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.theme; + +public enum ContrastRule { + HIGH_CONTRAST, + STANDARD +} diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/DarculaTheme.java b/core/src/main/java/com/github/weisj/darklaf/theme/DarculaTheme.java index c1251131..a529c8ca 100644 --- a/core/src/main/java/com/github/weisj/darklaf/theme/DarculaTheme.java +++ b/core/src/main/java/com/github/weisj/darklaf/theme/DarculaTheme.java @@ -49,12 +49,12 @@ public class DarculaTheme extends Theme { } @Override - public boolean isDark() { - return true; + public StyleRule getStyleRule() { + return StyleRule.DARK; } @Override - protected IconTheme getPresetIconTheme() { - return IconTheme.DARK; + protected PresetIconRule getPresetIconRule() { + return PresetIconRule.DARK; } } diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/DefaultThemeProvider.java b/core/src/main/java/com/github/weisj/darklaf/theme/DefaultThemeProvider.java new file mode 100644 index 00000000..1dc3c2c3 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/DefaultThemeProvider.java @@ -0,0 +1,91 @@ +/* + * 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.theme; + +public class DefaultThemeProvider implements ThemeProvider { + + private final Theme lightTheme; + private final Theme darkTheme; + private final Theme lightHighContrastTheme; + private final Theme darkHighContrastTheme; + + public DefaultThemeProvider() { + this(new IntelliJTheme(), new DarculaTheme(), + new HighContrastLightTheme(), new HighContrastDarkTheme()); + } + + public DefaultThemeProvider(final Theme lightTheme, + final Theme darkTheme, + final Theme lightHighContrastTheme, + final Theme darkHighContrastTheme) { + /* + * Ensure the given themes actually serve the purpose they are intended for. + */ + if (Theme.isDark(lightTheme)) { + throw new UnsupportedThemeException("Given light theme " + lightTheme + + "is declared as dark"); + } + if (Theme.isDark(lightHighContrastTheme)) { + throw new UnsupportedThemeException("Given light high-contrast theme " + lightHighContrastTheme + + " is declared as dark"); + } + if (!Theme.isDark(darkTheme)) { + throw new UnsupportedThemeException("Given dark theme " + darkTheme + + "is not declared as dark"); + } + if (!Theme.isDark(darkHighContrastTheme)) { + throw new UnsupportedThemeException("Given dark high-contrast theme " + darkTheme + + "is not declared as dark"); + } + /* + * A high contrast theme may serve as a standard theme, but a standard theme should never be used + * for high contrast themes. + */ + if (!Theme.isHighContrast(lightHighContrastTheme)) { + throw new UnsupportedThemeException("Given light high-contrast theme " + lightHighContrastTheme + + " is not declared as high-contrast"); + } + if (!Theme.isHighContrast(darkHighContrastTheme)) { + throw new UnsupportedThemeException("Given dark high-contrast theme " + darkHighContrastTheme + + " is not declared as high-contrast"); + } + this.lightTheme = lightTheme; + this.darkTheme = darkTheme; + this.lightHighContrastTheme = lightHighContrastTheme; + this.darkHighContrastTheme = darkHighContrastTheme; + } + + + @Override + public Theme getTheme(final PreferredThemeStyle themeStyle) { + if (themeStyle == null) return lightTheme; + boolean dark = themeStyle.getStyleRule() == StyleRule.DARK; + boolean highContrast = themeStyle.getContrastRule() == ContrastRule.HIGH_CONTRAST; + Theme theme = dark ? highContrast ? darkHighContrastTheme : darkTheme + : highContrast ? lightHighContrastTheme : lightTheme; + // Apply the font size. + theme.setFontSizeRule(themeStyle.getFontSizeRule()); + return theme; + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/FontMapper.java b/core/src/main/java/com/github/weisj/darklaf/theme/FontMapper.java new file mode 100644 index 00000000..4c9be729 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/FontMapper.java @@ -0,0 +1,32 @@ +/* + * 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.theme; + +import javax.swing.*; +import java.awt.*; + +public interface FontMapper { + + Font map(final Font font, final UIDefaults defaults); +} diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/FontSizeRule.java b/core/src/main/java/com/github/weisj/darklaf/theme/FontSizeRule.java new file mode 100644 index 00000000..7d6f9321 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/FontSizeRule.java @@ -0,0 +1,51 @@ +/* + * 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.theme; + +public enum FontSizeRule { + DEFAULT("default"), + TINY("tiny"), + SMALLER("smaller"), + SMALL("small"), + MEDIUM("medium"), + LARGE("large"), + LARGER("larger"), + HUGE("huge"); + + private final String propertyKey; + private final PropertyFontMapper fontMapper; + + FontSizeRule(final String propertyKey) { + this.propertyKey = propertyKey; + fontMapper = new PropertyFontMapper(getPropertyKey()); + } + + public String getPropertyKey() { + return "fontSize." + propertyKey; + } + + public FontMapper getFontMapper() { + return fontMapper; + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/HighContrastDarkTheme.java b/core/src/main/java/com/github/weisj/darklaf/theme/HighContrastDarkTheme.java index 7c9b6665..85b43668 100644 --- a/core/src/main/java/com/github/weisj/darklaf/theme/HighContrastDarkTheme.java +++ b/core/src/main/java/com/github/weisj/darklaf/theme/HighContrastDarkTheme.java @@ -29,8 +29,8 @@ import java.util.Properties; public class HighContrastDarkTheme extends Theme { @Override - protected IconTheme getPresetIconTheme() { - return IconTheme.NONE; + protected PresetIconRule getPresetIconRule() { + return PresetIconRule.NONE; } @Override @@ -54,13 +54,13 @@ public class HighContrastDarkTheme extends Theme { } @Override - public boolean isDark() { - return true; + public StyleRule getStyleRule() { + return StyleRule.DARK; } @Override - public boolean isHighContrast() { - return true; + public ContrastRule getContrastRule() { + return ContrastRule.HIGH_CONTRAST; } @Override diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/HighContrastLightTheme.java b/core/src/main/java/com/github/weisj/darklaf/theme/HighContrastLightTheme.java index fbec1a4d..a29b40fd 100644 --- a/core/src/main/java/com/github/weisj/darklaf/theme/HighContrastLightTheme.java +++ b/core/src/main/java/com/github/weisj/darklaf/theme/HighContrastLightTheme.java @@ -29,8 +29,8 @@ import java.util.Properties; public class HighContrastLightTheme extends Theme { @Override - protected IconTheme getPresetIconTheme() { - return IconTheme.LIGHT; + protected PresetIconRule getPresetIconRule() { + return PresetIconRule.LIGHT; } @Override @@ -54,13 +54,13 @@ public class HighContrastLightTheme extends Theme { } @Override - public boolean isDark() { - return false; + public StyleRule getStyleRule() { + return StyleRule.LIGHT; } @Override - public boolean isHighContrast() { - return true; + public ContrastRule getContrastRule() { + return ContrastRule.HIGH_CONTRAST; } @Override diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/IntelliJTheme.java b/core/src/main/java/com/github/weisj/darklaf/theme/IntelliJTheme.java index 600772b2..5deb572d 100644 --- a/core/src/main/java/com/github/weisj/darklaf/theme/IntelliJTheme.java +++ b/core/src/main/java/com/github/weisj/darklaf/theme/IntelliJTheme.java @@ -37,13 +37,8 @@ public class IntelliJTheme extends Theme { } @Override - public boolean isDark() { - return false; - } - - @Override - protected IconTheme getPresetIconTheme() { - return IconTheme.LIGHT; + protected PresetIconRule getPresetIconRule() { + return PresetIconRule.LIGHT; } @Override @@ -61,6 +56,11 @@ public class IntelliJTheme extends Theme { return IntelliJTheme.class; } + @Override + public StyleRule getStyleRule() { + return StyleRule.LIGHT; + } + @Override public void loadUIProperties(final Properties properties, final UIDefaults currentDefaults) { super.loadUIProperties(properties, currentDefaults); diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/PreferredThemeStyle.java b/core/src/main/java/com/github/weisj/darklaf/theme/PreferredThemeStyle.java new file mode 100644 index 00000000..fdd1f820 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/PreferredThemeStyle.java @@ -0,0 +1,55 @@ +/* + * 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.theme; + +public class PreferredThemeStyle { + + private final ContrastRule contrastRule; + private final StyleRule styleRule; + private final FontSizeRule fontSizeRule; + + public PreferredThemeStyle(final ContrastRule contrastRule, + final StyleRule styleRule, + final FontSizeRule fontSizeRule) { + if (contrastRule == null) throw new IllegalArgumentException("null is not a valid contrast rule"); + if (styleRule == null) throw new IllegalArgumentException("null is not a valid style rule"); + if (fontSizeRule == null) throw new IllegalArgumentException("null is not a valid font size rule"); + this.contrastRule = contrastRule; + this.styleRule = styleRule; + this.fontSizeRule = fontSizeRule; + } + + public ContrastRule getContrastRule() { + return contrastRule; + } + + public StyleRule getStyleRule() { + return styleRule; + } + + public FontSizeRule getFontSizeRule() { + return fontSizeRule; + } + +} diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/PresetIconRule.java b/core/src/main/java/com/github/weisj/darklaf/theme/PresetIconRule.java new file mode 100644 index 00000000..8c70e5c9 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/PresetIconRule.java @@ -0,0 +1,30 @@ +/* + * 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.theme; + +public enum PresetIconRule { + NONE, + DARK, + LIGHT +} diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/PropertyFontMapper.java b/core/src/main/java/com/github/weisj/darklaf/theme/PropertyFontMapper.java new file mode 100644 index 00000000..dcb6a18e --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/PropertyFontMapper.java @@ -0,0 +1,71 @@ +/* + * 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.theme; + +import com.github.weisj.darklaf.LafManager; + +import javax.swing.*; +import java.awt.*; +import java.util.logging.Logger; + +public class PropertyFontMapper implements FontMapper { + + private static final Logger LOGGER = Logger.getLogger(PropertyFontMapper.class.getName()); + + private Theme lastTheme = null; + private int adjustment; + private String propertyKey; + + public PropertyFontMapper(final String propertyKey) { + this.propertyKey = propertyKey; + } + + @Override + public Font map(final Font font, final UIDefaults defaults) { + adjustment = getSize(defaults); + // No need to create a new font. + if (adjustment == 0) return font; + if (adjustment < font.getSize2D()) { + if (adjustment != Integer.MIN_VALUE) { + LOGGER.warning("Font " + font + " would be invisible after applying " + + "an adjustment of " + adjustment + ". Aborting!"); + } + return font; + } + return font.deriveFont(font.getSize2D() + adjustment); + } + + private int getSize(final UIDefaults defaults) { + // Use cached value if already queried. + if (lastTheme == LafManager.getTheme()) return adjustment; + lastTheme = LafManager.getTheme(); + Object obj = defaults.get(propertyKey); + if (!(obj instanceof Integer)) { + LOGGER.warning("Font size property '" + propertyKey + "' not specified. Mapper will do nothing"); + return Integer.MIN_VALUE; + } else { + return (int) obj; + } + } +} diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/SolarizedDarkTheme.java b/core/src/main/java/com/github/weisj/darklaf/theme/SolarizedDarkTheme.java index 24fa8a4d..ce0c9584 100644 --- a/core/src/main/java/com/github/weisj/darklaf/theme/SolarizedDarkTheme.java +++ b/core/src/main/java/com/github/weisj/darklaf/theme/SolarizedDarkTheme.java @@ -49,8 +49,8 @@ public class SolarizedDarkTheme extends Theme { } @Override - public boolean isDark() { - return true; + public StyleRule getStyleRule() { + return StyleRule.DARK; } @Override @@ -60,7 +60,7 @@ public class SolarizedDarkTheme extends Theme { } @Override - protected IconTheme getPresetIconTheme() { - return IconTheme.NONE; + protected PresetIconRule getPresetIconRule() { + return PresetIconRule.NONE; } } diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/SolarizedLightTheme.java b/core/src/main/java/com/github/weisj/darklaf/theme/SolarizedLightTheme.java index 12c45156..9541766c 100644 --- a/core/src/main/java/com/github/weisj/darklaf/theme/SolarizedLightTheme.java +++ b/core/src/main/java/com/github/weisj/darklaf/theme/SolarizedLightTheme.java @@ -49,18 +49,18 @@ public class SolarizedLightTheme extends Theme { } @Override - public void loadUIProperties(final Properties properties, final UIDefaults currentDefaults) { - super.loadUIProperties(properties, currentDefaults); - loadCustomProperties("ui", properties, currentDefaults); + public StyleRule getStyleRule() { + return StyleRule.LIGHT; } @Override - public boolean isDark() { - return false; + public void loadUIProperties(final Properties properties, final UIDefaults currentDefaults) { + super.loadUIProperties(properties, currentDefaults); + loadCustomProperties("ui", properties, currentDefaults); } @Override - protected IconTheme getPresetIconTheme() { - return IconTheme.NONE; + protected PresetIconRule getPresetIconRule() { + return PresetIconRule.NONE; } } diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/StyleRule.java b/core/src/main/java/com/github/weisj/darklaf/theme/StyleRule.java new file mode 100644 index 00000000..48685ee1 --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/StyleRule.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.theme; + +public enum StyleRule { + DARK, + LIGHT +} diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/Theme.java b/core/src/main/java/com/github/weisj/darklaf/theme/Theme.java index cc1b36e7..167b9d38 100644 --- a/core/src/main/java/com/github/weisj/darklaf/theme/Theme.java +++ b/core/src/main/java/com/github/weisj/darklaf/theme/Theme.java @@ -57,6 +57,30 @@ public abstract class Theme { private static final String[] ICON_PROPERTIES = new String[]{ "control", "dialog", "files", "frame", "indicator", "menu", "misc", "navigation" }; + private FontSizeRule fontSizeRule; + + + /** + * Returns whether the theme is a dark theme. This is used to determine the default mode for [aware] icons. + * + * @param theme the theme. + * @return true if dark. + */ + public static boolean isDark(final Theme theme) { + if (theme == null) return false; + return theme.getStyleRule() == StyleRule.DARK; + } + + /** + * Returns whether the theme is a high contrast theme. + * + * @param theme the theme. + * @return true if the theme is a high contrast theme. + */ + public static boolean isHighContrast(final Theme theme) { + if (theme == null) return false; + return theme.getContrastRule() == ContrastRule.HIGH_CONTRAST; + } public UIManager.LookAndFeelInfo createLookAndFeelInfo() { return new UIManager.LookAndFeelInfo(getPrefix(), DarkLaf.class.getCanonicalName()); @@ -130,7 +154,7 @@ public abstract class Theme { * @param currentDefaults the current ui defaults. */ protected void loadIconTheme(final Properties properties, final UIDefaults currentDefaults) { - IconTheme iconTheme = getPresetIconTheme(); + PresetIconRule iconTheme = getPresetIconRule(); Properties props; switch (iconTheme) { case DARK: @@ -185,7 +209,7 @@ public abstract class Theme { * * @return the icon theme. */ - protected abstract IconTheme getPresetIconTheme(); + protected abstract PresetIconRule getPresetIconRule(); /** * Load custom properties that are located under {@link #getResourcePath()}, with the name {@link @@ -310,24 +334,50 @@ public abstract class Theme { } /** - * Returns whether this theme is a dark theme. This is used to determine the default mode for [aware] icons. + * Returns the style rule for this theme. * - * @return true if the theme is dark. + * @return the style rule. */ - public abstract boolean isDark(); + public abstract StyleRule getStyleRule(); /** - * Returns whether the theme is a high contrast theme. + * Returns contrast rule for the theme. * - * @return true if the theme is high contrast. + * @return the contrast rule. */ - public boolean isHighContrast() { - return false; + public ContrastRule getContrastRule() { + return ContrastRule.STANDARD; } - protected enum IconTheme { - NONE, - DARK, - LIGHT + /** + * Get the font size rule for this theme. + * + * @return the font size rule. + */ + public FontSizeRule getFontSizeRule() { + if (fontSizeRule == null) fontSizeRule = FontSizeRule.DEFAULT; + return fontSizeRule; + } + + /** + * Set the font size rule. + * + * @param fontSizeRule the font size rule. + */ + public void setFontSizeRule(final FontSizeRule fontSizeRule) { + this.fontSizeRule = fontSizeRule; } + + /** + * Get the font mapper for the specified size rule. By default, this delegated to the values specified by the + * `[rule].size` properties. + * + * @param rule the font size rule. + * @return the associated font mapper. + */ + public FontMapper getFontMapper(final FontSizeRule rule) { + if (rule == null) return (font, defaults) -> font; + return rule.getFontMapper(); + } + } diff --git a/core/src/main/java/com/github/weisj/darklaf/theme/ThemeProvider.java b/core/src/main/java/com/github/weisj/darklaf/theme/ThemeProvider.java new file mode 100644 index 00000000..22429fff --- /dev/null +++ b/core/src/main/java/com/github/weisj/darklaf/theme/ThemeProvider.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.theme; + +public interface ThemeProvider { + + Theme getTheme(final PreferredThemeStyle themeStyle); +} diff --git a/core/src/main/resources/com/github/weisj/darklaf/properties/font.properties b/core/src/main/resources/com/github/weisj/darklaf/properties/font.properties index 421c1452..bf30ef9b 100644 --- a/core/src/main/resources/com/github/weisj/darklaf/properties/font.properties +++ b/core/src/main/resources/com/github/weisj/darklaf/properties/font.properties @@ -22,45 +22,45 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # -Button.font = withSize(12)withStyle(0) -CheckBox.font = withSize(12)withStyle(0) -CheckBoxMenuItem.font = withSize(12)withStyle(0) -ColorChooser.font = withSize(12)withStyle(0) -ComboBox.font = withSize(12)withStyle(0) -DesktopIcon.font = withSize(12)withStyle(0) -EditorPane.font = withSize(12)withStyle(0) -FormattedTextField.font = withSize(12)withStyle(0) -IconButton.font = withSize(12)withStyle(0) -Label.font = withSize(12)withStyle(0) -List.font = withSize(12)withStyle(0) -Menu.font = withSize(12)withStyle(0) -MenuBar.font = withSize(12)withStyle(0) -MenuItem.font = withSize(12)withStyle(0) -OptionPane.font = withSize(12)withStyle(0) -Panel.font = withSize(12)withStyle(0) -PasswordField.font = withSize(12)withStyle(0) -PopupMenu.font = withSize(12)withStyle(0) -ProgressBar.font = withSize(12)withStyle(0) -RadioButton.font = withSize(12)withStyle(0) -RadioButtonMenuItem.font = withSize(12)withStyle(0) -ScrollPane.font = withSize(12)withStyle(0) -Slider.font = withSize(12)withStyle(0) -Spinner.font = withSize(12)withStyle(0) -TabbedPane.font = withSize(12)withStyle(0) -TabFrameTab.font = from(Label.font)withSize(11)withStyle(0) -Table.font = withSize(12)withStyle(0) -TableHeader.font = withSize(12)withStyle(0) -TextArea.font = withSize(12)withStyle(0) -TextField.font = withSize(12)withStyle(0) -TextPane.font = withSize(12)withStyle(0) -TitledBorder.font = withSize(12)withStyle(0) -ToggleButton.font = withSize(12)withStyle(0) -ToolBar.font = withSize(12)withStyle(0) -ToolTip.font = withSize(12)withStyle(0) -Tree.font = withSize(12)withStyle(0) -Viewport.font = withSize(12)withStyle(0) -MenuItem.acceleratorFont = withSize(10)withStyle(0) -RadioButtonMenuItem.acceleratorFont = withSize(10)withStyle(0) -Menu.acceleratorFont = withSize(10)withStyle(0) -CheckBoxMenuItem.acceleratorFont = withSize(10)withStyle(0) -InternalFrame.titleFont = withSize(11)withStyle(0) +Button.font = withSize(%fontSize.default)withStyle(0) +CheckBox.font = withSize(%fontSize.default)withStyle(0) +CheckBoxMenuItem.font = withSize(%fontSize.default)withStyle(0) +ColorChooser.font = withSize(%fontSize.default)withStyle(0) +ComboBox.font = withSize(%fontSize.default)withStyle(0) +DesktopIcon.font = withSize(%fontSize.default)withStyle(0) +EditorPane.font = withSize(%fontSize.default)withStyle(0) +FormattedTextField.font = withSize(%fontSize.default)withStyle(0) +IconButton.font = withSize(%fontSize.default)withStyle(0) +Label.font = withSize(%fontSize.default)withStyle(0) +List.font = withSize(%fontSize.default)withStyle(0) +Menu.font = withSize(%fontSize.default)withStyle(0) +MenuBar.font = withSize(%fontSize.default)withStyle(0) +MenuItem.font = withSize(%fontSize.default)withStyle(0) +OptionPane.font = withSize(%fontSize.default)withStyle(0) +Panel.font = withSize(%fontSize.default)withStyle(0) +PasswordField.font = withSize(%fontSize.default)withStyle(0) +PopupMenu.font = withSize(%fontSize.default)withStyle(0) +ProgressBar.font = withSize(%fontSize.default)withStyle(0) +RadioButton.font = withSize(%fontSize.default)withStyle(0) +RadioButtonMenuItem.font = withSize(%fontSize.default)withStyle(0) +ScrollPane.font = withSize(%fontSize.default)withStyle(0) +Slider.font = withSize(%fontSize.default)withStyle(0) +Spinner.font = withSize(%fontSize.default)withStyle(0) +TabbedPane.font = withSize(%fontSize.default)withStyle(0) +TabFrameTab.font = from(Label.font)withSize(%fontSize.default,-1)withStyle(0) +Table.font = withSize(%fontSize.default)withStyle(0) +TableHeader.font = withSize(%fontSize.default)withStyle(0) +TextArea.font = withSize(%fontSize.default)withStyle(0) +TextField.font = withSize(%fontSize.default)withStyle(0) +TextPane.font = withSize(%fontSize.default)withStyle(0) +TitledBorder.font = withSize(%fontSize.default)withStyle(0) +ToggleButton.font = withSize(%fontSize.default)withStyle(0) +ToolBar.font = withSize(%fontSize.default)withStyle(0) +ToolTip.font = withSize(%fontSize.default)withStyle(0) +Tree.font = withSize(%fontSize.default)withStyle(0) +Viewport.font = withSize(%fontSize.default)withStyle(0) +MenuItem.acceleratorFont = withSize(%fontSize.default,-2)withStyle(0) +RadioButtonMenuItem.acceleratorFont = withSize(%fontSize.default,-2)withStyle(0) +Menu.acceleratorFont = withSize(%fontSize.default,-2)withStyle(0) +CheckBoxMenuItem.acceleratorFont = withSize(%fontSize.default,-2)withStyle(0) +InternalFrame.titleFont = withSize(%fontSize.default,-1)withStyle(0) diff --git a/core/src/main/resources/com/github/weisj/darklaf/properties/font_sizes.properties b/core/src/main/resources/com/github/weisj/darklaf/properties/font_sizes.properties new file mode 100644 index 00000000..c98899ba --- /dev/null +++ b/core/src/main/resources/com/github/weisj/darklaf/properties/font_sizes.properties @@ -0,0 +1,35 @@ +# suppress inspection "UnusedProperty" for whole file +# +# 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. +# +# The default font size to use. +fontSize.default = 12 + +# The following values are all relative to the default font size (or those specified on 'font.properties') +fontSize.tiny = -6 +fontSize.smaller = -4 +fontSize.small = -2 +fontSize.medium = 0 +fontSize.large = 4 +fontSize.larger = 8 +fontSize.huge = 12 diff --git a/core/src/test/java/theme/MyCustomTheme.java b/core/src/test/java/theme/MyCustomTheme.java index 03244c0f..ac0e4130 100644 --- a/core/src/test/java/theme/MyCustomTheme.java +++ b/core/src/test/java/theme/MyCustomTheme.java @@ -23,6 +23,8 @@ */ package theme; +import com.github.weisj.darklaf.theme.PresetIconRule; +import com.github.weisj.darklaf.theme.StyleRule; import com.github.weisj.darklaf.theme.Theme; import com.github.weisj.darklaf.util.SystemInfo; @@ -60,12 +62,12 @@ public class MyCustomTheme extends Theme { } @Override - protected IconTheme getPresetIconTheme() { + protected PresetIconRule getPresetIconRule() { /* * Use a custom icon theme. Colors are defined in * my_custom_theme_icons.properties. */ - return IconTheme.NONE; + return PresetIconRule.NONE; } @Override @@ -84,7 +86,8 @@ public class MyCustomTheme extends Theme { } @Override - public boolean isDark() { - return false; + public StyleRule getStyleRule() { + return StyleRule.LIGHT; } + } diff --git a/property-loader/src/main/java/com/github/weisj/darklaf/PropertyLoader.java b/property-loader/src/main/java/com/github/weisj/darklaf/PropertyLoader.java index 110ec574..05cea998 100644 --- a/property-loader/src/main/java/com/github/weisj/darklaf/PropertyLoader.java +++ b/property-loader/src/main/java/com/github/weisj/darklaf/PropertyLoader.java @@ -158,19 +158,7 @@ public final class PropertyLoader { } else if (PropertyValue.NULL.equalsIgnoreCase(value)) { returnVal = null; } else if (value.startsWith(String.valueOf(REFERENCE_PREFIX))) { - String val = parseKey(value); - String referenceFreeKey = val.substring(1); - boolean containsKey = accumulator.containsKey(val) - || (addReferenceInfo && accumulator.containsKey(referenceFreeKey)); - if (!containsKey) { - LOGGER.warning("Could not reference value '" + val + "' while loading '" + key + "'. " + - "May be a forward reference"); - } - returnVal = accumulator.get(val); - if (addReferenceInfo) { - if (returnVal == null) returnVal = accumulator.get(referenceFreeKey); - returnVal = new Pair<>(value, returnVal); - } + returnVal = parseReference(key, value, accumulator); } if (returnVal instanceof LoadError) { final Color color = ColorUtil.fromHex(value, null); @@ -191,6 +179,24 @@ public final class PropertyLoader { return value; } + private static Object parseReference(final String key, final String value, + final Map accumulator) { + String val = parseKey(value); + String referenceFreeKey = val.substring(1); + boolean containsKey = accumulator.containsKey(val) + || (addReferenceInfo && accumulator.containsKey(referenceFreeKey)); + if (!containsKey) { + LOGGER.warning("Could not reference value '" + val + "' while loading '" + key + "'. " + + "Maybe is a forward reference"); + } + Object returnVal = accumulator.get(val); + if (addReferenceInfo) { + if (returnVal == null) returnVal = accumulator.get(referenceFreeKey); + returnVal = new Pair<>(value, returnVal); + } + return returnVal; + } + private static Object parseInsets(final String value) { final List numbers = StringUtil.split(value, String.valueOf(SEPARATOR)); @@ -214,11 +220,11 @@ public final class PropertyLoader { base = result.getFirst(); val = result.getSecond(); } else if (val.startsWith(FONT_SIZE)) { - Pair result = parseFontAttribute(FONT_SIZE, val); + Pair result = parseFontAttribute(FONT_SIZE, val, accumulator); size = result.getFirst(); val = result.getSecond(); } else if (val.startsWith(FONT_STYLE)) { - Pair result = parseFontAttribute(FONT_STYLE, val); + Pair result = parseFontAttribute(FONT_STYLE, val, accumulator); style = result.getFirst(); val = result.getSecond(); } else { @@ -243,16 +249,31 @@ public final class PropertyLoader { } } - private static Pair parseFontAttribute(final String identifier, final String val) { + private static Pair parseFontAttribute(final String identifier, final String val, + final Map accumulator) { String key = val.substring(identifier.length() + 1); int lastIndex = key.indexOf(ARG_END); String rest = key.substring(lastIndex + 1); key = key.substring(0, lastIndex); - try { - return new Pair<>(Integer.parseInt(key), rest); - } catch (NumberFormatException e) { - return new Pair<>(-1, rest); + String[] subKeys = key.split(String.valueOf(SEPARATOR)); + int[] values = new int[subKeys.length]; + for (int i = 0; i < values.length; i++) { + if (subKeys[i].startsWith(String.valueOf(REFERENCE_PREFIX))) { + Object ref = parseReference(identifier, subKeys[i], accumulator); + values[i] = ref instanceof Integer ? (Integer) ref : 0; + } else { + try { + values[i] = Integer.parseInt(subKeys[i]); + } catch (NumberFormatException ignored) { + // In this case the value will be 0. + } + } + } + int result = 0; + for (int i : values) { + result += i; } + return new Pair<>(result, rest); } private static Pair parseFrom(final String val,