Browse Source

Initial support for choosing a theme by specifying a preferred style.

pull/127/head
weisj 5 years ago
parent
commit
4fc9f03de9
  1. 30
      core/src/main/java/com/github/weisj/darklaf/DarkLaf.java
  2. 53
      core/src/main/java/com/github/weisj/darklaf/LafManager.java
  3. 29
      core/src/main/java/com/github/weisj/darklaf/theme/ContrastRule.java
  4. 8
      core/src/main/java/com/github/weisj/darklaf/theme/DarculaTheme.java
  5. 91
      core/src/main/java/com/github/weisj/darklaf/theme/DefaultThemeProvider.java
  6. 32
      core/src/main/java/com/github/weisj/darklaf/theme/FontMapper.java
  7. 51
      core/src/main/java/com/github/weisj/darklaf/theme/FontSizeRule.java
  8. 12
      core/src/main/java/com/github/weisj/darklaf/theme/HighContrastDarkTheme.java
  9. 12
      core/src/main/java/com/github/weisj/darklaf/theme/HighContrastLightTheme.java
  10. 14
      core/src/main/java/com/github/weisj/darklaf/theme/IntelliJTheme.java
  11. 55
      core/src/main/java/com/github/weisj/darklaf/theme/PreferredThemeStyle.java
  12. 30
      core/src/main/java/com/github/weisj/darklaf/theme/PresetIconRule.java
  13. 71
      core/src/main/java/com/github/weisj/darklaf/theme/PropertyFontMapper.java
  14. 8
      core/src/main/java/com/github/weisj/darklaf/theme/SolarizedDarkTheme.java
  15. 14
      core/src/main/java/com/github/weisj/darklaf/theme/SolarizedLightTheme.java
  16. 29
      core/src/main/java/com/github/weisj/darklaf/theme/StyleRule.java
  17. 76
      core/src/main/java/com/github/weisj/darklaf/theme/Theme.java
  18. 29
      core/src/main/java/com/github/weisj/darklaf/theme/ThemeProvider.java
  19. 84
      core/src/main/resources/com/github/weisj/darklaf/properties/font.properties
  20. 35
      core/src/main/resources/com/github/weisj/darklaf/properties/font_sizes.properties
  21. 11
      core/src/test/java/theme/MyCustomTheme.java
  22. 59
      property-loader/src/main/java/com/github/weisj/darklaf/PropertyLoader.java

30
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<Object, Object> 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);
}

53
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
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

29
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
}

8
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;
}
}

91
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;
}
}

32
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);
}

51
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;
}
}

12
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

12
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

14
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);

55
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;
}
}

30
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
}

71
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;
}
}
}

8
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;
}
}

14
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;
}
}

29
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
}

76
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();
}
}

29
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);
}

84
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)

35
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

11
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;
}
}

59
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<Object, Object> 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<String> 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<Integer, String> result = parseFontAttribute(FONT_SIZE, val);
Pair<Integer, String> result = parseFontAttribute(FONT_SIZE, val, accumulator);
size = result.getFirst();
val = result.getSecond();
} else if (val.startsWith(FONT_STYLE)) {
Pair<Integer, String> result = parseFontAttribute(FONT_STYLE, val);
Pair<Integer, String> result = parseFontAttribute(FONT_STYLE, val, accumulator);
style = result.getFirst();
val = result.getSecond();
} else {
@ -243,16 +249,31 @@ public final class PropertyLoader {
}
}
private static Pair<Integer, String> parseFontAttribute(final String identifier, final String val) {
private static Pair<Integer, String> parseFontAttribute(final String identifier, final String val,
final Map<Object, Object> 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);
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 {
return new Pair<>(Integer.parseInt(key), rest);
} catch (NumberFormatException e) {
return new Pair<>(-1, rest);
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<Font, String> parseFrom(final String val,

Loading…
Cancel
Save