Browse Source

Migrate to new parsing system.

pull/235/head
weisj 4 years ago
parent
commit
159e1394f9
No known key found for this signature in database
GPG Key ID: 31124CB75461DA2A
  1. 44
      core/src/main/java/com/github/weisj/darklaf/task/AccentColorAdjustmentTask.java
  2. 24
      core/src/main/java/com/github/weisj/darklaf/task/ColorAdjustmentTask.java
  3. 33
      core/src/main/java/com/github/weisj/darklaf/task/ForegroundColorGenerationTask.java
  4. 4
      core/src/main/java/com/github/weisj/darklaf/task/ThemeDefaultsInitTask.java
  5. 6
      core/src/main/resources/com/github/weisj/darklaf/properties/font.properties
  6. 2
      core/src/main/resources/com/github/weisj/darklaf/properties/platform/linux.properties
  7. 2
      core/src/main/resources/com/github/weisj/darklaf/properties/platform/mac.properties
  8. 16
      core/src/main/resources/com/github/weisj/darklaf/properties/platform/windows.properties
  9. 12
      core/src/main/resources/com/github/weisj/darklaf/properties/ui/checkBox.properties
  10. 2
      core/src/main/resources/com/github/weisj/darklaf/properties/ui/numberingPane.properties
  11. 12
      core/src/main/resources/com/github/weisj/darklaf/properties/ui/radioButton.properties
  12. 1
      core/src/main/resources/com/github/weisj/darklaf/properties/ui/tabFrame.properties
  13. 2
      core/src/main/resources/com/github/weisj/darklaf/properties/ui/tabbedPane.properties
  14. 423
      property-loader/src/main/java/com/github/weisj/darklaf/PropertyLoader.java
  15. 13
      property-loader/src/main/java/com/github/weisj/darklaf/icons/IconColorMapper.java
  16. 36
      theme/src/main/resources/com/github/weisj/darklaf/theme/darcula/darcula_accents.properties
  17. 36
      theme/src/main/resources/com/github/weisj/darklaf/theme/intellij/intellij_accents.properties
  18. 42
      theme/src/main/resources/com/github/weisj/darklaf/theme/one_dark/one_dark_accents.properties
  19. 2
      theme/src/main/resources/com/github/weisj/darklaf/theme/solarized_dark/solarized_dark_accents.properties
  20. 38
      theme/src/main/resources/com/github/weisj/darklaf/theme/solarized_light/solarized_light_accents.properties

44
core/src/main/java/com/github/weisj/darklaf/task/AccentColorAdjustmentTask.java

@ -22,15 +22,18 @@
package com.github.weisj.darklaf.task;
import java.awt.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import com.github.weisj.darklaf.color.DarkColorModelHSB;
import com.github.weisj.darklaf.parser.Parser;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.uiresource.DarkColorUIResource;
import com.github.weisj.darklaf.util.LogUtil;
import com.github.weisj.darklaf.util.Pair;
import com.github.weisj.darklaf.util.Types;
public class AccentColorAdjustmentTask extends ColorAdjustmentTask {
@ -67,16 +70,16 @@ public class AccentColorAdjustmentTask extends ColorAdjustmentTask {
private void adjustColors(final String listKey, final Color c, final Properties listProperties,
final Properties properties) {
adjust(listKey, listProperties, list -> {
adjust(listKey, listProperties, map -> {
double[] hsb = DarkColorModelHSB.RGBtoHSBValues(c.getRed(), c.getGreen(), c.getBlue());
adjustColorList(list, hsb, properties);
adjustColorList(map, hsb, properties);
});
}
private void adjustColorList(final List<?> list, final double[] hsb, final Properties properties) {
private void adjustColorList(final Map<?, ?> map, final double[] hsb, final Properties properties) {
ColorInfo info = new ColorInfo();
for (Object o : list) {
setColorInfo(o, info);
for (Map.Entry<?, ?> entry : map.entrySet()) {
setColorInfo(entry, info);
if (info.key == null) continue;
Object c = mapColor(info, hsb, properties);
if (c instanceof Color) {
@ -88,25 +91,24 @@ public class AccentColorAdjustmentTask extends ColorAdjustmentTask {
}
}
private void setColorInfo(final Object o, final ColorInfo info) {
private void setColorInfo(final Map.Entry<?, ?> o, final ColorInfo info) {
info.set(null, 0, 0, 0);
if (o instanceof String) {
info.set(o.toString(), 100, 100, 100);
String targetKey = Types.safeCast(o.getKey(), String.class);
List<?> modifiers = o.getValue() == Parser.EMPTY_VALUE
? Arrays.asList(100, 100, 100)
: Types.safeCast(o.getValue(), List.class);
if (targetKey == null) {
LOGGER.severe("Target key is null");
return;
}
if (o instanceof Pair<?, ?>) {
Object first = ((Pair<?, ?>) o).getFirst();
Object second = ((Pair<?, ?>) o).getSecond();
if (!(first instanceof String)) return;
if (!(second instanceof List<?>)) return;
String key = first.toString();
List<?> list = (List<?>) second;
if (list.size() != 3 || !(list.get(0) instanceof Integer) || !(list.get(1) instanceof Integer)
|| !(list.get(2) instanceof Integer)) {
return;
}
info.set(key, (Integer) list.get(0), (Integer) list.get(1), (Integer) list.get(2));
if (modifiers == null || modifiers.size() != 3
|| !(modifiers.get(0) instanceof Integer)
|| !(modifiers.get(1) instanceof Integer)
|| !(modifiers.get(2) instanceof Integer)) {
LOGGER.severe("Incorrect modifier list " + modifiers);
return;
}
info.set(targetKey, (Integer) modifiers.get(0), (Integer) modifiers.get(1), (Integer) modifiers.get(2));
}
private Object mapColor(final ColorInfo info, final double[] hsbMatch, final Properties properties) {

24
core/src/main/java/com/github/weisj/darklaf/task/ColorAdjustmentTask.java

@ -21,19 +21,23 @@
*/
package com.github.weisj.darklaf.task;
import java.awt.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.logging.Logger;
import javax.swing.*;
import com.github.weisj.darklaf.PropertyLoader;
import com.github.weisj.darklaf.parser.ParseResult;
import com.github.weisj.darklaf.parser.Parser;
import com.github.weisj.darklaf.parser.ParserContext;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.util.DarkUIUtil;
import com.github.weisj.darklaf.util.LogUtil;
public abstract class ColorAdjustmentTask implements DefaultsAdjustmentTask {
private static final Logger LOGGER = LogUtil.getLogger(ColorAdjustmentTask.class);
protected static final UIDefaults DEFAULTS = new UIDefaults();
@Override
@ -51,11 +55,15 @@ public abstract class ColorAdjustmentTask implements DefaultsAdjustmentTask {
DEFAULTS.clear();
}
protected void adjust(final String listKey, final Properties listProperties, final Consumer<List<?>> action) {
Object obj = PropertyLoader.parseValue(listKey, listProperties.getProperty(listKey), listProperties, DEFAULTS,
DarkUIUtil.ICON_LOADER);
if (obj instanceof List<?>) {
action.accept((List<?>) obj);
protected void adjust(final String listKey, final Properties listProperties, final Consumer<Map<?, ?>> action) {
ParseResult p = Parser.parse(Parser.createParseResult(listKey, listProperties.getProperty(listKey)),
new ParserContext(listProperties, DEFAULTS, DarkUIUtil.ICON_LOADER));
Object obj = p.result;
if (obj instanceof Map<?, ?>) {
action.accept((Map<?, ?>) obj);
} else if (listProperties.contains(listKey)) {
LOGGER.severe("Expected map object but got " + obj + "[" + obj.getClass() + "]."
+ " Declared as " + listProperties.getProperty(listKey) + " with key " + listKey);
}
}
}

33
core/src/main/java/com/github/weisj/darklaf/task/ForegroundColorGenerationTask.java

@ -23,7 +23,9 @@ package com.github.weisj.darklaf.task;
import java.awt.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Logger;
import javax.swing.plaf.ColorUIResource;
@ -33,10 +35,11 @@ import com.github.weisj.darklaf.color.DarkColorModelHSL;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.theme.info.AccentColorRule;
import com.github.weisj.darklaf.uiresource.DarkColorUIResource;
import com.github.weisj.darklaf.util.Pair;
import com.github.weisj.darklaf.util.LogUtil;
public class ForegroundColorGenerationTask extends ColorAdjustmentTask {
private static final Logger LOGGER = LogUtil.getLogger(ForegroundColorGenerationTask.class);
private static final String FOREGROUND_LIST_KEY = "selectionForeground.propertyList";
private static final String ACCENT_LIST_KEY = "accentForeground.propertyList";
private static final double MIN_FOREGROUND_DIFFERENCE = 0.5;
@ -52,17 +55,33 @@ public class ForegroundColorGenerationTask extends ColorAdjustmentTask {
Properties props = currentTheme.loadPropertyFile("accents", true);
AccentColorRule accentColorRule = currentTheme.getAccentColorRule();
if (accentColorRule.getAccentColor() != null && currentTheme.supportsCustomAccentColor()) {
adjust(ACCENT_LIST_KEY, props, list -> adjustForegroundList(list, properties));
adjust(ACCENT_LIST_KEY, props, map -> adjustForegroundList(map, properties));
}
if (accentColorRule.getSelectionColor() != null && currentTheme.supportsCustomSelectionColor()) {
adjust(FOREGROUND_LIST_KEY, props, list -> adjustForegroundList(list, properties));
adjust(FOREGROUND_LIST_KEY, props, map -> adjustForegroundList(map, properties));
}
}
private void adjustForegroundList(final List<?> list, final Properties properties) {
list.stream().filter(o -> o instanceof Pair<?, ?>).map(Pair.class::cast)
.filter(p -> p.getFirst() instanceof Color)
.forEach(p -> properties.put(p.getSecond(), makeForeground((Color) p.getFirst())));
private void adjustForegroundList(final Map<?, ?> map, final Properties properties) {
map.entrySet().stream()
.filter(e -> e.getKey() instanceof Color)
.forEach(e -> {
Object targets = e.getValue();
Color c = makeForeground((Color) e.getKey());
if (targets instanceof String) {
properties.put(targets.toString(), c);
} else if (targets instanceof List) {
for (Object target : (List<?>) targets) {
if (target instanceof String) {
properties.put(target.toString(), c);
} else {
LOGGER.warning("Invalid target " + target);
}
}
} else {
LOGGER.warning("Invalid target declaration " + targets);
}
});
}
public static ColorUIResource makeForeground(final Color bg) {

4
core/src/main/java/com/github/weisj/darklaf/task/ThemeDefaultsInitTask.java

@ -93,8 +93,8 @@ public class ThemeDefaultsInitTask implements DefaultsInitTask {
}
private void backupAccentColors(final Properties uiProps) {
uiProps.put(ACCENT_COLOR_BACKUP_KEY, Objects
.requireNonNull(uiProps.get(PropertyLoader.asKey(ACCENT_COLOR_SOURCE_KEY)), ACCENT_COLOR_SOURCE_KEY));
uiProps.put(ACCENT_COLOR_BACKUP_KEY, Objects.requireNonNull(
uiProps.get(PropertyLoader.asKey(ACCENT_COLOR_SOURCE_KEY)), ACCENT_COLOR_SOURCE_KEY));
uiProps.put(SELECTION_COLOR_BACKUP_KEY, Objects.requireNonNull(
uiProps.get(PropertyLoader.asKey(SELECTION_COLOR_SOURCE_KEY)), SELECTION_COLOR_SOURCE_KEY));
}

6
core/src/main/resources/com/github/weisj/darklaf/properties/font.properties

@ -50,7 +50,7 @@ ScrollPane.font = withSize(%fontSize.default)withStyle(0)
Slider.font = withSize(%fontSize.default,-2)withStyle(0)
Spinner.font = withSize(%fontSize.default)withStyle(0)
TabbedPane.font = withSize(%fontSize.default)withStyle(0)
TabFrameTab.font = from(Label.font)withSize(%fontSize.title)withStyle(0)
TabFrameTab.font = from(%Label.font)withSize(%fontSize.title)withStyle(0)
Table.font = withSize(%fontSize.default)withStyle(0)
TableHeader.font = withSize(%fontSize.default)withStyle(0)
TextArea.font = withSize(%fontSize.default)withStyle(0)
@ -68,5 +68,5 @@ Menu.acceleratorFont = withSize(%fontSize.accelerator)withStyle(0
CheckBoxMenuItem.acceleratorFont = withSize(%fontSize.accelerator)withStyle(0)
InternalFrame.titleFont = withSize(%fontSize.title)withStyle(0)
kerning.allowList = ?:{__all__}
kerning.blockList = ?:{}
kerning.allowList = ?:[__all__]
kerning.blockList = ?:[]

2
core/src/main/resources/com/github/weisj/darklaf/properties/platform/linux.properties

@ -30,4 +30,4 @@ Tree.alternateRowColor = false
List.alternateRowColor = false
PopupMenu.defaultLightWeightPopups = false
kerning.blockList = {Table.font}
kerning.blockList = [Table.font]

2
core/src/main/resources/com/github/weisj/darklaf/properties/platform/mac.properties

@ -55,4 +55,4 @@ Tree.expanded.unselected.focused.icon = navigation/arrow/thick/arrowDown.svg[
Tree.expanded.unselected.unfocused.icon = navigation/arrow/thick/arrowDown.svg[themed]
Tree.expanded.disabled.icon = navigation/arrow/thick/arrowRightDisabled.svg[themed]
kerning.blockList = {Table.font}
kerning.blockList = [Table.font]

16
core/src/main/resources/com/github/weisj/darklaf/properties/platform/windows.properties

@ -33,11 +33,11 @@ List.alternateRowColor = false
PopupMenu.defaultLightWeightPopups = true
PopupMenu.defaultLightWeightPopups.windows10 = false
kerning.blockList = {NumberingPane.font;\
FormattedTextField.font;\
EditorPane.font;\
PasswordField.font;\
TextPane.font;\
TextArea.font;\
TextField.font;\
Table.font}
kerning.blockList = [NumberingPane.font,\
FormattedTextField.font,\
EditorPane.font,\
PasswordField.font,\
TextPane.font,\
TextArea.font,\
TextField.font,\
Table.font]

12
core/src/main/resources/com/github/weisj/darklaf/properties/ui/checkBox.properties

@ -42,12 +42,12 @@ CheckBox.borderInsets = 2,3,3,0
CheckBox.visualInsets = 0,3,0,0
#Icons
CheckBox.icon = {control/checkBox.svg[themed](19,19);\
control/checkBoxDisabled.svg[themed](19,19);\
control/checkBoxFocused.svg[themed](19,19);\
control/checkBoxSelected.svg[themed](19,19);\
control/checkBoxSelectedDisabled.svg[themed](19,19);\
control/checkBoxSelectedFocused.svg[themed](19,19)}
CheckBox.icon = [control/checkBox.svg[themed](19,19),\
control/checkBoxDisabled.svg[themed](19,19),\
control/checkBoxFocused.svg[themed](19,19),\
control/checkBoxSelected.svg[themed](19,19),\
control/checkBoxSelectedDisabled.svg[themed](19,19),\
control/checkBoxSelectedFocused.svg[themed](19,19)]
CheckBox.unchecked.icon = control/checkBox.svg[themed](19,19)
CheckBox.uncheckedDisabled.icon = control/checkBoxDisabled.svg[themed](19,19)
CheckBox.uncheckedFocused.icon = control/checkBoxFocused.svg[themed](19,19)

2
core/src/main/resources/com/github/weisj/darklaf/properties/ui/numberingPane.properties

@ -32,4 +32,4 @@ NumberingPane.background = %textBackgroundSecondaryInactive
NumberingPane.textBackground = %textBackgroundSecondary
NumberingPane.currentLineForeground = %textForeground
NumberingPane.currentLineBackground = %textSelectionBackgroundSecondary
NumberingPane.font = Monospace-0-10
NumberingPane.font = font(Monospace-0-10)

12
core/src/main/resources/com/github/weisj/darklaf/properties/ui/radioButton.properties

@ -43,12 +43,12 @@ RadioButton.borderInsets = 2,2,2,0
RadioButton.visualInsets = 0,2,0,0
#Icons
RadioButton.icon = {control/radio.svg[themed](19,19);\
control/radioDisabled.svg[themed](19,19);\
control/radioFocused.svg[themed](19,19);\
control/radioSelected.svg[themed](19,19);\
control/radioSelectedDisabled.svg[themed](19,19);\
control/radioSelectedFocused.svg[themed](19,19)}
RadioButton.icon = [control/radio.svg[themed](19,19),\
control/radioDisabled.svg[themed](19,19),\
control/radioFocused.svg[themed](19,19),\
control/radioSelected.svg[themed](19,19),\
control/radioSelectedDisabled.svg[themed](19,19),\
control/radioSelectedFocused.svg[themed](19,19)]
RadioButton.unchecked.icon = control/radio.svg[themed](19,19)
RadioButton.uncheckedDisabled.icon = control/radioDisabled.svg[themed](19,19)
RadioButton.uncheckedFocused.icon = control/radioFocused.svg[themed](19,19)

1
core/src/main/resources/com/github/weisj/darklaf/properties/ui/tabFrame.properties

@ -46,7 +46,6 @@ TabFramePopup.closeTooltipTextHint = shift ESC
TabFramePopup.headerButton.tooltipInsets = 5,5,5,5
TabFramePopup.headerButton.insets = 4,4,4,4
TabFramePopup.minimumHeaderSize = null
TabFramePopup.borderColor = %border

2
core/src/main/resources/com/github/weisj/darklaf/properties/ui/tabbedPane.properties

@ -55,7 +55,7 @@ TabbedPane.selectedLabelShift = 0
TabbedPane.selectedTabPadInsets = 0,0,0,0
TabbedPane.tabAreaInsets = 0,0,0,0
TabbedPane.moreTabsButton.font = Monospace-0-10
TabbedPane.moreTabsButton.font = font(Monospace-0-10)
TabbedPane.moreTabsButton.foreground = %textForegroundSecondary
TabbedPane.moreTabsButton.pad = 2
TabbedPane.newTabButton.pad = 2

423
property-loader/src/main/java/com/github/weisj/darklaf/PropertyLoader.java

@ -21,29 +21,20 @@
*/
package com.github.weisj.darklaf;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.text.AttributedCharacterIterator;
import java.util.*;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.swing.*;
import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.InsetsUIResource;
import com.github.weisj.darklaf.color.ColorUtil;
import com.github.weisj.darklaf.icons.DarkUIAwareIcon;
import com.github.weisj.darklaf.icons.EmptyIcon;
import com.github.weisj.darklaf.icons.IconLoader;
import com.github.weisj.darklaf.icons.StateIcon;
import com.github.weisj.darklaf.uiresource.DarkColorUIResource;
import com.github.weisj.darklaf.uiresource.DarkFontUIResource;
import com.github.weisj.darklaf.parser.ParseResult;
import com.github.weisj.darklaf.parser.Parser;
import com.github.weisj.darklaf.parser.ParserContext;
import com.github.weisj.darklaf.util.*;
/**
@ -53,40 +44,8 @@ import com.github.weisj.darklaf.util.*;
public final class PropertyLoader {
private static final Logger LOGGER = LogUtil.getLogger(PropertyLoader.class);
private static final IconLoader ICON_LOADER = IconLoader.get(IconLoader.class);
private static final char INT_LIST_START = '[';
private static final char INT_LIST_END = ']';
private static final String DUAL_KEY = "[dual]";
private static final String AWARE_KEY = "[aware]";
private static final String THEMED_KEY = "[themed]";
private static final String ICON_EMPTY = "empty";
private static final char REFERENCE_PREFIX = '%';
private static final String FALLBACK_PREFIX = "?:";
private static final String FONT_FROM = "from";
private static final String FONT_SIZE = "withSize";
private static final String FONT_STYLE = "withStyle";
private static final char FONT_DELIMITER = '-';
private static final char LIST_START = '{';
private static final char LIST_END = '}';
private static final char ARG_START = '(';
private static final char ARG_END = ')';
private static final char SEPARATOR = ',';
private static final char LIST_SEPARATOR = ';';
private static final char PAIR_SEPARATOR = ':';
private static boolean debugMode;
private static final Map<AttributedCharacterIterator.Attribute, Integer> attributes = Collections.emptyMap();
public static void setDebugMode(final boolean debugMode) {
PropertyLoader.debugMode = debugMode;
}
public static boolean isDebugMode() {
return debugMode;
}
public static Properties loadProperties(final Class<?> clazz, final String name, final String path) {
final Properties properties = new Properties();
@ -120,15 +79,21 @@ public final class PropertyLoader {
public static void putProperties(final Map<Object, Object> properties, final Set<String> keys,
final Map<Object, Object> accumulator, final UIDefaults currentDefaults, final IconLoader iconLoader) {
ParserContext context = new ParserContext(accumulator, currentDefaults, iconLoader);
for (final String key : keys) {
final String value = properties.get(key).toString();
Object parsed = parseValue(key, value, accumulator, currentDefaults, iconLoader);
if (parsed != null) {
String k = parseKey(key);
if (parsed instanceof FallbackValue && accumulator.containsKey(k)) continue;
accumulator.put(parseKey(key), parsed);
} else {
currentDefaults.remove(parseKey(key));
ParseResult parseResult = Parser.parse(Parser.createParseResult(key, value), context);
if (parseResult.finished) {
Object result = parseResult.result;
if (result != null) {
if (Parser.isDebugMode()) {
accumulator.put(parseResult.key, parseResult);
} else {
accumulator.put(parseResult.key, result);
}
} else {
currentDefaults.remove(parseResult.key);
}
}
}
}
@ -157,362 +122,12 @@ public final class PropertyLoader {
.forEach(e -> Optional.ofNullable(mapper.apply((Map.Entry<Object, T>) e)).ifPresent(e::setValue));
}
private static String parseKey(final String key) {
if (debugMode) return key;
return key.startsWith(String.valueOf(REFERENCE_PREFIX)) ? key.substring(1) : key;
}
public static Object parseValue(final String propertyKey, final String val, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults, final IconLoader iconLoader) {
if (val == null || PropertyValue.NULL.equals(val)) {
return null;
}
String key = propertyKey;
boolean isFallback = val.startsWith(FALLBACK_PREFIX);
String value = !isFallback ? val : val.substring(FALLBACK_PREFIX.length());
boolean skipObjects = false;
if (key.startsWith(String.valueOf(REFERENCE_PREFIX))) {
skipObjects = true;
}
key = parseKey(key);
final Color color = ColorUtil.fromHex(value, null);
final Integer invVal = getInteger(value);
final Boolean boolVal = PropertyValue.TRUE.equalsIgnoreCase(value) ? Boolean.TRUE
: PropertyValue.FALSE.equalsIgnoreCase(value) ? Boolean.FALSE : null;
if (color != null && (value.length() == 6 || value.length() == 8)) {
return maybeWrap(new DarkColorUIResource(color), isFallback);
} else if (invVal != null) {
return maybeWrap(invVal, isFallback);
} else if (boolVal != null) {
return maybeWrap(boolVal, isFallback);
}
Object returnVal = new LoadError();
if (key.endsWith("Insets") || key.endsWith(".insets") || key.endsWith(".margins")) {
returnVal = parseInsets(value, accumulator, currentDefaults, iconLoader);
} else if (!skipObjects && (key.endsWith("Border") || key.endsWith(".border") || key.endsWith("Renderer"))) {
return maybeWrap((UIDefaults.LazyValue) def -> parseObject(value), isFallback);
} else if (key.endsWith(".component") || key.endsWith("Component")) {
return maybeWrap((UIDefaults.ActiveValue) (def) -> parseObject(value), isFallback);
} else if (key.toLowerCase().endsWith("font")) {
returnVal = parseFont(key, value, accumulator, currentDefaults);
} else if (key.endsWith(".icon") || key.endsWith("Icon") || key.endsWith("Image")) {
returnVal = parseIcon(value, accumulator, currentDefaults, iconLoader);
} else if (key.endsWith("Size") || key.endsWith(".size")) {
returnVal = parseSize(value);
} else if (value.startsWith(String.valueOf(LIST_START)) && value.endsWith(String.valueOf(LIST_END))) {
returnVal = parseList((v, acc, defs, iconL) -> PropertyLoader.parseValue("", v, acc, defs, iconL), value,
accumulator, currentDefaults, iconLoader);
} else if (value.startsWith(String.valueOf(INT_LIST_START)) && value.endsWith(String.valueOf(INT_LIST_END))) {
returnVal = parseList((SimpleValueMapper<Integer>) Integer::parseInt, value, accumulator, currentDefaults,
iconLoader, INT_LIST_START, INT_LIST_END, SEPARATOR);
} else if (value.contains(String.valueOf(PAIR_SEPARATOR))) {
returnVal = parsePair((v, acc, defs, iconL) -> PropertyLoader.parseValue("", v, acc, defs, iconL), value,
accumulator, currentDefaults, iconLoader);
} else if (PropertyValue.NULL.equalsIgnoreCase(value)) {
returnVal = null;
} else if (value.startsWith(String.valueOf(REFERENCE_PREFIX))) {
returnVal = parseReference(key, value, accumulator, currentDefaults);
}
if (!(returnVal instanceof LoadError)) return maybeWrap(returnVal, isFallback);
return maybeWrap(value, isFallback);
}
private static Object maybeWrap(final Object value, final boolean isDefaultValue) {
return !isDefaultValue ? value : new FallbackValue(value);
}
private static <T> Pair<T, T> parsePair(final ParseFunction<T> mapper, final String value,
final Map<Object, Object> accumulator, final Map<Object, Object> currentDefaults,
final IconLoader iconLoader) {
return parsePair(mapper, mapper, value, accumulator, currentDefaults, iconLoader);
}
private static <T, K> Pair<T, K> parsePair(final ParseFunction<T> firstMapper, final ParseFunction<K> secondMapper,
final String value, final Map<Object, Object> accumulator, final Map<Object, Object> currentDefaults,
final IconLoader iconLoader) {
String[] pairVals = value.split(String.valueOf(PAIR_SEPARATOR), 2);
return new Pair<>(firstMapper.parseValue(pairVals[0], accumulator, currentDefaults, iconLoader),
secondMapper.parseValue(pairVals[1], accumulator, currentDefaults, iconLoader));
}
private static Object parseReference(final String key, final String value, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefault) {
String val = parseKey(value);
String referenceFreeKey = val.substring(1);
boolean accumulatorContainsKey =
accumulator.containsKey(val) || (debugMode && accumulator.containsKey(referenceFreeKey));
boolean defaultsContainKey =
currentDefault.containsKey(val) || (debugMode && currentDefault.containsKey(referenceFreeKey));
if (!defaultsContainKey && !accumulatorContainsKey) {
LOGGER.warning("Could not reference value '" + val + "' while loading '" + key + "'. "
+ "Maybe is a forward reference");
}
Object returnVal = accumulatorContainsKey ? accumulator.get(val) : currentDefault.get(val);
if (debugMode) {
if (returnVal == null) {
returnVal = accumulatorContainsKey ? accumulator.get(referenceFreeKey) : currentDefault.get(val);
}
returnVal = new ReferenceInfo<>(value, returnVal);
}
return returnVal;
}
private static Object parseInsets(final String value, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults, final IconLoader iconLoader) {
List<Integer> insets = parseList((SimpleValueMapper<Integer>) Integer::parseInt, value, accumulator,
currentDefaults, iconLoader, Character.MIN_VALUE, Character.MIN_VALUE, SEPARATOR);
return new InsetsUIResource(insets.get(0), insets.get(1), insets.get(2), insets.get(3));
}
@SuppressWarnings("MagicConstant")
private static Object parseFont(final String key, final String value, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults) {
String val = value;
Font base = null;
int size = -1;
int style = -1;
while (true) {
if (val.startsWith(FONT_FROM)) {
Pair<Font, String> result = parseFrom(val, accumulator, currentDefaults);
base = result.getFirst();
val = result.getSecond();
} else if (val.startsWith(FONT_SIZE)) {
Pair<Integer, String> result = parseFontAttribute(FONT_SIZE, val, accumulator, currentDefaults);
size = result.getFirst();
val = result.getSecond();
} else if (val.startsWith(FONT_STYLE)) {
Pair<Integer, String> result = parseFontAttribute(FONT_STYLE, val, accumulator, currentDefaults);
style = result.getFirst();
val = result.getSecond();
} else {
break;
}
if (val.isEmpty()) break;
}
if (base == null) base = parseExplicitFont(value);
if (base == null) base = Types.safeCast(accumulator.get(key), Font.class);
if (base == null) base = Types.safeCast(currentDefaults.get(key), Font.class);
if (base == null) base = FontUtil.createFont(null, Font.PLAIN, 12);
if (size <= 0) size = base.getSize();
if (style < 0) style = base.getStyle();
Font font = base.deriveFont(style, size);
font = new DarkFontUIResource(font.deriveFont(attributes));
return font;
}
private static Font parseExplicitFont(final String value) {
try {
final String[] decode = value.split(String.valueOf(FONT_DELIMITER));
return FontUtil.createFont(decode[0], Integer.parseInt(decode[1]), Integer.parseInt(decode[2]));
} catch (final Exception e) {
return null;
}
}
private static Pair<Integer, String> parseFontAttribute(final String identifier, final String val,
final Map<Object, Object> accumulator, final Map<Object, Object> currrentDefault) {
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 = unpackReference(parseReference(identifier, subKeys[i], accumulator, currrentDefault));
values[i] = Types.safeCast(ref, Integer.class, 0);
} else {
try {
values[i] = Integer.parseInt(subKeys[i]);
} catch (final NumberFormatException ignored) {
// In this case the value will be 0.
}
}
}
int result = 0;
for (int i : values) {
result += i;
}
return new Pair<>(result, rest);
}
public static Object unpackReference(final Object object) {
Object obj = object;
while (obj instanceof ReferenceInfo) {
obj = ((ReferenceInfo<?>) obj).getValue();
}
return obj;
}
private static Pair<Font, String> parseFrom(final String val, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults) {
String key = val.substring(FONT_FROM.length() + 1);
int index = key.indexOf(ARG_END);
String rest = key.substring(index + 1);
key = key.substring(0, index);
Font font = Types.safeCast(accumulator.get(key), Font.class);
if (font == null) font = Types.safeCast(currentDefaults.get(key), Font.class);
return new Pair<>(font, rest);
}
private static <T> List<T> parseList(final ParseFunction<T> mapper, final String value,
final Map<Object, Object> accumulator, final Map<Object, Object> currentDefaults,
final IconLoader iconLoader) {
return parseList(mapper, value, accumulator, currentDefaults, iconLoader, LIST_START, LIST_END, LIST_SEPARATOR);
}
private static <T> List<T> parseList(final ParseFunction<T> mapper, final String value,
final Map<Object, Object> accumulator, final Map<Object, Object> currentDefaults,
final IconLoader iconLoader,
final char start, final char end, final char delimiter) {
if (value == null || value.isEmpty()) return new ArrayList<>();
String val = value;
if (val.charAt(0) == start) {
val = value.substring(1, value.length() - 1);
}
String[] values = val.split(String.valueOf(delimiter));
if (values.length == 0) return Collections.emptyList();
return Arrays.stream(values).map(k -> mapper.parseValue(k, accumulator, currentDefaults, iconLoader))
.collect(Collectors.toList());
}
private static Icon parseIcon(final String value, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults, final IconLoader iconLoader) {
if (value.startsWith(String.valueOf(LIST_START))) {
return parseStateIcon(value, accumulator, currentDefaults, iconLoader);
}
String path = value;
Dimension dim = new Dimension(16, 16);
if (value.charAt(value.length() - 1) == ARG_END) {
int i = path.lastIndexOf(ARG_START);
String dimVal = path.substring(i + 1, path.length() - 1);
int[] values =
Arrays.stream(dimVal.split(String.valueOf(SEPARATOR), 2)).mapToInt(Integer::parseInt).toArray();
dim.width = values[0];
dim.height = values[1];
path = path.substring(0, i);
}
if (path.charAt(path.length() - 1) == INT_LIST_END) {
String tag = null;
if (path.endsWith(DUAL_KEY)) {
tag = DUAL_KEY;
} else if (path.endsWith(AWARE_KEY)) {
tag = AWARE_KEY;
} else if (path.endsWith(THEMED_KEY)) {
tag = THEMED_KEY;
}
if (tag == null) {
throw new IllegalArgumentException("Invalid tag on icon path: '" + value + "'");
}
String iconPath = path.substring(0, path.length() - tag.length());
if (tag.equals(THEMED_KEY)) {
return iconLoader.getIcon(iconPath, dim.width, dim.height, true);
} else {
DarkUIAwareIcon icon = iconLoader.getUIAwareIcon(iconPath, dim.width, dim.height);
if (tag.equals(DUAL_KEY)) {
return icon.getDual();
} else {
return icon;
}
}
}
if (path.equals(ICON_EMPTY)) {
return EmptyIcon.create(dim.width, dim.height);
}
return iconLoader.getIcon(path, dim.width, dim.height);
}
private static Icon parseStateIcon(final String value, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults, final IconLoader iconLoader) {
return new StateIcon(parseList(PropertyLoader::parseIcon, value, accumulator, currentDefaults, iconLoader));
}
private static Object parseSize(final String value) {
try {
int[] dim = Arrays.stream(value.split(String.valueOf(SEPARATOR), 2)).mapToInt(Integer::parseInt).toArray();
return new DimensionUIResource(dim[0], dim[1]);
} catch (IndexOutOfBoundsException | NumberFormatException e) {
return new LoadError();
}
}
private static Integer getInteger(final String value) {
try {
return Integer.parseInt(value);
} catch (final NumberFormatException ignored) {
return null;
}
}
private static Double getDouble(final String value) {
try {
return Double.parseDouble(value);
} catch (final NumberFormatException ignored) {
return null;
}
}
private static Object parseObject(final String value) {
try {
return Class.forName(value).getDeclaredConstructor().newInstance();
} catch (final Exception ignored) {
}
return null;
}
public static String asKey(final String key) {
if (debugMode) return REFERENCE_PREFIX + key;
return key;
}
public static String getReferencePrefix() {
return String.valueOf(REFERENCE_PREFIX);
}
private static final class LoadError {
}
private interface ParseFunction<T> {
T parseValue(final String value, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults,
final IconLoader iconLoader);
}
private interface SimpleValueMapper<T> extends ParseFunction<T> {
T map(final String value);
@Override
default T parseValue(final String value, final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults, final IconLoader iconLoader) {
return map(value);
}
}
public static class ReferenceInfo<T> extends Pair<String, T> {
public ReferenceInfo(final String key, final T value) {
super(key, value);
}
public String getReferenceKey() {
return getFirst();
}
public T getValue() {
return getSecond();
}
}
private static class FallbackValue {
private final Object value;
private FallbackValue(final Object value) {
this.value = value;
}
public static String asKey(final String key) {
// if (Parser.isDebugMode()) return getReferencePrefix() + key;
return key;
}
}

13
property-loader/src/main/java/com/github/weisj/darklaf/icons/IconColorMapper.java

@ -31,6 +31,9 @@ import javax.swing.*;
import com.github.weisj.darklaf.PropertyLoader;
import com.github.weisj.darklaf.color.ColorUtil;
import com.github.weisj.darklaf.parser.ParseResult;
import com.github.weisj.darklaf.parser.Parser;
import com.github.weisj.darklaf.parser.ParserContext;
import com.github.weisj.darklaf.util.LogUtil;
import com.github.weisj.darklaf.util.Pair;
import com.github.weisj.darklaf.util.Types;
@ -286,11 +289,11 @@ public final class IconColorMapper {
currentKey = i < 0 ? key : fallbacks[i];
int retryCount = 5;
if (i >= 0 && currentKey instanceof String && ((String) currentKey).startsWith(INLINE_VALUE_PREFIX)) {
obj = Types.safeCast(PropertyLoader.parseValue(
Objects.toString(key),
((String) currentKey).substring(INLINE_VALUE_PREFIX.length()), map,
contextDefaults, IconLoader.get()),
type);
ParseResult p = Parser.parse(
Parser.createParseResult(Objects.toString(key),
((String) currentKey).substring(INLINE_VALUE_PREFIX.length())),
new ParserContext(map, contextDefaults, IconLoader.get()));
obj = Types.safeCast(p.result, type);
}
do {
if (obj == null) {

36
theme/src/main/resources/com/github/weisj/darklaf/theme/darcula/darcula_accents.properties

@ -24,24 +24,24 @@
#
# suppress inspection "UnusedProperty" for whole file
#
accent.propertyList = {widgetFillDefault:[100,100,100];\
hoverHighlightDefault:[100,80,80];\
clickHighlightDefault:[100,90,85];\
widgetBorderDefault:[100,80,110];\
controlBorderFocus:[100,90,116];\
controlBorderFocusSelected:[100,90,116];\
glowFocusLine:[100,90,116];\
glowFocusLineInactive:[100,90,116];\
glowFocus:[100,120,155];\
glowFocusInactive:[100,120,155];\
borderFocus:[100,76,122];\
highlightFill:[100,80,45];\
highlightFillFocus:[100,100,80];\
highlightFillFocusSecondary:[100,110,100];\
highlightFillMono:[100,25,50];\
controlFillHighlight:[100,100,100];\
controlFillHighlightDisabled:[100,77,50];\
accent.propertyList = {widgetFillDefault:[100,100,100],\
hoverHighlightDefault:[100,80,80],\
clickHighlightDefault:[100,90,85],\
widgetBorderDefault:[100,80,110],\
controlBorderFocus:[100,90,116],\
controlBorderFocusSelected:[100,90,116],\
glowFocusLine:[100,90,116],\
glowFocusLineInactive:[100,90,116],\
glowFocus:[100,120,155],\
glowFocusInactive:[100,120,155],\
borderFocus:[100,76,122],\
highlightFill:[100,80,45],\
highlightFillFocus:[100,100,80],\
highlightFillFocusSecondary:[100,110,100],\
highlightFillMono:[100,25,50],\
controlFillHighlight:[100,100,100],\
controlFillHighlightDisabled:[100,77,50],\
hyperlink:[100,100,100]}
selection.propertyList = {textCompSelectionBackground;textSelectionBackground}
selection.propertyList = {textCompSelectionBackground,textSelectionBackground}
selectionForeground.propertyList = {%textCompSelectionBackground:textCompSelectionForeground}

36
theme/src/main/resources/com/github/weisj/darklaf/theme/intellij/intellij_accents.properties

@ -24,24 +24,24 @@
#
# suppress inspection "UnusedProperty" for whole file
#
accent.propertyList = {widgetFillDefault:[100,100,100];\
hoverHighlightDefault:[100,80,100];\
clickHighlightDefault:[100,90,100];\
widgetBorderDefault:[100,100,90];\
controlBorderFocus:[100,60,100];\
controlBorderFocusSelected:[100,50,122];\
glowFocusLine:[100,60,100];\
glowFocusLineInactive:[100,60,100];\
glowFocus:[100,120,120];\
glowFocusInactive:[100,120,120];\
borderFocus:[100,76,122];\
highlightFillFocus:[100,130,95];\
highlightFillFocusSecondary:[100,110,100];\
highlightFillMono:[100,25,90];\
controlBorderSelected:[100,100,100];\
widgetFillSelected:[100,100,100];\
controlFillHighlight:[100,100,100];\
accent.propertyList = {widgetFillDefault:[100,100,100],\
hoverHighlightDefault:[100,80,100],\
clickHighlightDefault:[100,90,100],\
widgetBorderDefault:[100,100,90],\
controlBorderFocus:[100,60,100],\
controlBorderFocusSelected:[100,50,122],\
glowFocusLine:[100,60,100],\
glowFocusLineInactive:[100,60,100],\
glowFocus:[100,120,120],\
glowFocusInactive:[100,120,120],\
borderFocus:[100,76,122],\
highlightFillFocus:[100,130,95],\
highlightFillFocusSecondary:[100,110,100],\
highlightFillMono:[100,25,90],\
controlBorderSelected:[100,100,100],\
widgetFillSelected:[100,100,100],\
controlFillHighlight:[100,100,100],\
hyperlink:[100,100,100]}
selection.propertyList = {textCompSelectionBackground;textSelectionBackground}
selection.propertyList = {textCompSelectionBackground,textSelectionBackground}
selectionForeground.propertyList = {%textCompSelectionBackground:textCompSelectionForeground}

42
theme/src/main/resources/com/github/weisj/darklaf/theme/one_dark/one_dark_accents.properties

@ -24,27 +24,27 @@
#
# suppress inspection "UnusedProperty" for whole file
#
accent.propertyList = {widgetFillDefault:[100,100,100];\
hoverHighlightDefault:[100,80,80];\
clickHighlightDefault:[100,90,85];\
widgetBorderDefault:[100,80,110];\
controlBorderFocus:[100,90,116];\
controlBorderFocusSelected:[100,90,116];\
glowFocusLine:[100,90,116];\
glowFocusLineInactive:[100,90,116];\
glowFocus:[100,120,155];\
glowFocusInactive:[100,120,155];\
borderFocus:[100,76,122];\
highlightFill:[100,80,45];\
highlightFillFocus:[100,100,80];\
highlightFillFocusSecondary:[100,110,100];\
highlightFillMono:[100,50,50];\
controlFillHighlight:[100,100,100];\
controlFillSecondary:[100,100,100];\
controlFadeStart:[100,100,100];\
controlFadeEnd:[100,50,30];\
controlFillHighlightDisabled:[100,77,50];\
accent.propertyList = {widgetFillDefault:[100,100,100],\
hoverHighlightDefault:[100,80,80],\
clickHighlightDefault:[100,90,85],\
widgetBorderDefault:[100,80,110],\
controlBorderFocus:[100,90,116],\
controlBorderFocusSelected:[100,90,116],\
glowFocusLine:[100,90,116],\
glowFocusLineInactive:[100,90,116],\
glowFocus:[100,120,155],\
glowFocusInactive:[100,120,155],\
borderFocus:[100,76,122],\
highlightFill:[100,80,45],\
highlightFillFocus:[100,100,80],\
highlightFillFocusSecondary:[100,110,100],\
highlightFillMono:[100,50,50],\
controlFillHighlight:[100,100,100],\
controlFillSecondary:[100,100,100],\
controlFadeStart:[100,100,100],\
controlFadeEnd:[100,50,30],\
controlFillHighlightDisabled:[100,77,50],\
hyperlink:[100,100,100]}
selection.propertyList = {textCompSelectionBackground;textSelectionBackground}
selection.propertyList = {textCompSelectionBackground,textSelectionBackground}
selectionForeground.propertyList = {%textCompSelectionBackground:textCompSelectionForeground}

2
theme/src/main/resources/com/github/weisj/darklaf/theme/solarized_dark/solarized_dark_accents.properties

@ -24,6 +24,6 @@
#
# suppress inspection "UnusedProperty" for whole file
#
selection.propertyList = {textCompSelectionBackground;textSelectionBackground}
selection.propertyList = {textCompSelectionBackground,textSelectionBackground}
selectionForeground.propertyList = {%textCompSelectionBackground:textCompSelectionForeground}

38
theme/src/main/resources/com/github/weisj/darklaf/theme/solarized_light/solarized_light_accents.properties

@ -24,25 +24,25 @@
#
# suppress inspection "UnusedProperty" for whole file
#
accent.propertyList = {widgetFillDefault:[100,100,100];\
dropForeground:[104,73,95];\
acceleratorForeground:[104,73,95];\
borderFocus:[98,130,113];\
hoverHighlightDefault:[100,89,103];\
clickHighlightDefault:[100,80,107];\
highlightFillFocus:[103,90,100];\
highlightFillFocusSecondary:[100,108,103];\
widgetBorderDefault:[102,98,94];\
controlBorderFocus:[99,54,110];\
controlBorderFocusSelected:[99,54,110];\
glowFocus:[100,100,100];\
glowFocusInactive:[100,100,100];\
glowFocusLine:[98,43,100];\
glowFocusLineInactive:[98,43,100];\
controlBorderSelected:[100,100,100];\
widgetFillSelected:[100,100,100];\
controlFillHighlight:[100,100,100];\
accent.propertyList = {widgetFillDefault:[100,100,100],\
dropForeground:[104,73,95],\
acceleratorForeground:[104,73,95],\
borderFocus:[98,130,113],\
hoverHighlightDefault:[100,89,103],\
clickHighlightDefault:[100,80,107],\
highlightFillFocus:[103,90,100],\
highlightFillFocusSecondary:[100,108,103],\
widgetBorderDefault:[102,98,94],\
controlBorderFocus:[99,54,110],\
controlBorderFocusSelected:[99,54,110],\
glowFocus:[100,100,100],\
glowFocusInactive:[100,100,100],\
glowFocusLine:[98,43,100],\
glowFocusLineInactive:[98,43,100],\
controlBorderSelected:[100,100,100],\
widgetFillSelected:[100,100,100],\
controlFillHighlight:[100,100,100],\
hyperlink:[100,100,100]}
selection.propertyList = {textCompSelectionBackground;textSelectionBackground}
selection.propertyList = {textCompSelectionBackground,textSelectionBackground}
selectionForeground.propertyList = {%textCompSelectionBackground:textCompSelectionForeground}

Loading…
Cancel
Save