Browse Source

Refactored defaults initialization.

pull/127/head
weisj 5 years ago
parent
commit
6bdf10857f
  1. 339
      core/src/main/java/com/github/weisj/darklaf/DarkLaf.java
  2. 62
      core/src/main/java/com/github/weisj/darklaf/LafManager.java
  3. 11
      core/src/main/java/com/github/weisj/darklaf/components/border/DarkBorders.java
  4. 3
      core/src/main/java/com/github/weisj/darklaf/platform/Decorations.java
  5. 3
      core/src/main/java/com/github/weisj/darklaf/platform/DefaultDecorationsProvider.java
  6. 33
      core/src/main/java/com/github/weisj/darklaf/task/DefaultsInitTask.java
  7. 114
      core/src/main/java/com/github/weisj/darklaf/task/FontDefaultsInitTask.java
  8. 95
      core/src/main/java/com/github/weisj/darklaf/task/IdeaDefaultsInitTask.java
  9. 108
      core/src/main/java/com/github/weisj/darklaf/task/InputDefaultsInitTask.java
  10. 44
      core/src/main/java/com/github/weisj/darklaf/task/PlatformDefaultsInitTask.java
  11. 50
      core/src/main/java/com/github/weisj/darklaf/task/SystemDefaultsInitTask.java
  12. 99
      core/src/main/java/com/github/weisj/darklaf/task/ThemeDefaultsInitTask.java
  13. 39
      core/src/main/java/com/github/weisj/darklaf/task/UserPreferenceInitTask.java
  14. 50
      core/src/main/java/com/github/weisj/darklaf/task/UtilityDefaultsInitTask.java
  15. 4
      core/src/main/java/com/github/weisj/darklaf/theme/FontMapper.java
  16. 6
      core/src/main/java/com/github/weisj/darklaf/theme/PropertyFontMapper.java
  17. 12
      core/src/main/java/com/github/weisj/darklaf/theme/Theme.java
  18. 3
      decorations-base/src/main/java/com/github/weisj/darklaf/decorations/DecorationsProvider.java
  19. 3
      macos/src/main/java/com/github/weisj/darklaf/platform/macos/MacOSDecorationsProvider.java
  20. 42
      property-loader/src/main/java/com/github/weisj/darklaf/PropertyLoader.java
  21. 3
      windows/src/main/java/com/github/weisj/darklaf/platform/windows/WindowsDecorationsProvider.java

339
core/src/main/java/com/github/weisj/darklaf/DarkLaf.java

@ -23,32 +23,16 @@
*/
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.task.*;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.ui.DarkPopupFactory;
import com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuUI;
import com.github.weisj.darklaf.util.DarkUIUtil;
import com.github.weisj.darklaf.util.SystemInfo;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.font.TextAttribute;
import java.text.AttributedCharacterIterator;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -59,7 +43,18 @@ public class DarkLaf extends BasicLookAndFeel {
public static final String SYSTEM_PROPERTY_PREFIX = "darklaf.";
private static final Logger LOGGER = Logger.getLogger(DarkLaf.class.getName());
private static final String NAME = "Darklaf";
/*
* All tasks for initializing the ui defaults in order of execution.
*/
private static final DefaultsInitTask[] INIT_TASKS = new DefaultsInitTask[]{
new ThemeDefaultsInitTask(),
new InputDefaultsInitTask(),
new IdeaDefaultsInitTask(),
new FontDefaultsInitTask(),
new UtilityDefaultsInitTask(),
new SystemDefaultsInitTask(),
new PlatformDefaultsInitTask()
};
private final BasicLookAndFeel base;
/**
@ -100,85 +95,15 @@ public class DarkLaf extends BasicLookAndFeel {
}
}
@Override
public UIDefaults getDefaults() {
final UIDefaults metalDefaults = new MetalLookAndFeel().getDefaults();
final UIDefaults defaults = base.getDefaults();
final Theme currentTheme = LafManager.getTheme();
try {
initInputMapDefaults(defaults);
loadThemeDefaults(currentTheme, defaults);
setupUtils(defaults);
initIdeaDefaults(defaults);
patchComboBox(metalDefaults, defaults);
if (SystemInfo.isMac) {
patchMacOSFonts(defaults);
}
applyFontRule(currentTheme, defaults);
setupDecorations();
String key = DarkPopupMenuUI.KEY_DEFAULT_LIGHTWEIGHT_POPUPS;
if (SystemInfo.isWindows10 && Decorations.isCustomDecorationSupported()) {
JPopupMenu.setDefaultLightWeightPopupEnabled(defaults.getBoolean(key + ".windows"));
} else {
JPopupMenu.setDefaultLightWeightPopupEnabled(defaults.getBoolean(key));
}
// Update border colors.
DarkBorders.update(defaults);
return defaults;
} catch (final Exception e) {
LOGGER.log(Level.SEVERE, e.toString(), e.getStackTrace());
}
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);
DarkUIUtil.setShadowOpacity(defaults.getInt("shadowOpacity") / 100f);
}
private void patchMacOSFonts(final UIDefaults defaults) {
for (Map.Entry<Object, Object> entry : defaults.entrySet()) {
if (entry.getValue() instanceof Font) {
Font font = (Font) entry.getValue();
entry.setValue(macOSFontFromFont(font));
}
}
}
private Font macOSFontFromFont(final Font font) {
Map<AttributedCharacterIterator.Attribute, Integer> attributes = Collections.singletonMap(TextAttribute.KERNING,
TextAttribute.KERNING_ON);
String fontName = SystemInfo.isMacOSCatalina ? ".AppleSystemUIFont" : ".SF NS Text";
Font macFont = new Font(fontName, font.getStyle(), font.getSize()).deriveFont(attributes);
if (font instanceof UIResource) {
macFont = new FontUIResource(macFont);
}
return macFont == null ? font : macFont;
public void initialize() {
/*
* On macOS the default PopupFactory is overwritten with a custom one, which always uses heavyweight popups.
* This is disadvantageous for the behaviour of custom tooltips.
*/
base.initialize();
PopupFactory.setSharedInstance(new DarkPopupFactory());
setupDecorations();
}
private void setupDecorations() {
@ -187,157 +112,28 @@ public class DarkLaf extends BasicLookAndFeel {
JDialog.setDefaultLookAndFeelDecorated(true);
}
protected void adjustPlatformSpecifics(final Properties uiProps) {
boolean useScreenMenuBar = Boolean.getBoolean("apple.laf.useScreenMenuBar");
// If user wants to use Apple menu bar, then we need to keep the default
// component for MenuBarUI and MenuUI
if (SystemInfo.isMac && useScreenMenuBar) {
uiProps.remove("MenuBarUI");
@Override
public void uninitialize() {
base.uninitialize();
DarkPopupMenuUI.MouseGrabber mouseGrabber = DarkPopupMenuUI.getMouseGrabber();
if (mouseGrabber != null) {
mouseGrabber.uninstall();
}
}
@Override
public String getName() {
return NAME;
}
@SuppressWarnings({"HardCodedStringLiteral"})
private static void initInputMapDefaults(final UIDefaults defaults) {
// Make ENTER work in JTrees
final InputMap treeInputMap = (InputMap) defaults.get("Tree.focusInputMap");
if (treeInputMap != null) {
// it's really possible. For example, GTK+ doesn't have such map
treeInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "toggle");
}
// Cut/Copy/Paste in JTextAreas
final InputMap textAreaInputMap = (InputMap) defaults.get("TextArea.focusInputMap");
if (textAreaInputMap != null) {
// It really can be null, for example when LAF isn't properly initialized
// (Alloy license problem)
installCutCopyPasteShortcuts(textAreaInputMap, false);
}
// Cut/Copy/Paste in JTextFields
final InputMap textFieldInputMap = (InputMap) defaults.get("TextField.focusInputMap");
if (textFieldInputMap != null) {
// It really can be null, for example when LAF isn't properly initialized
// (Alloy license problem)
installCutCopyPasteShortcuts(textFieldInputMap, false);
}
// Cut/Copy/Paste in JPasswordField
final InputMap passwordFieldInputMap = (InputMap) defaults.get("PasswordField.focusInputMap");
if (passwordFieldInputMap != null) {
// It really can be null, for example when LAF isn't properly initialized
// (Alloy license problem)
installCutCopyPasteShortcuts(passwordFieldInputMap, false);
}
// Cut/Copy/Paste in JTables
final InputMap tableInputMap = (InputMap) defaults.get("Table.ancestorInputMap");
if (tableInputMap != null) {
// It really can be null, for example when LAF isn't properly initialized
// (Alloy license problem)
installCutCopyPasteShortcuts(tableInputMap, true);
}
final InputMap buttonInputMap = (InputMap) defaults.get("Button.focusInputMap");
if (buttonInputMap != null && !SystemInfo.isMac) {
buttonInputMap.put(KeyStroke.getKeyStroke("ENTER"), "pressed");
buttonInputMap.put(KeyStroke.getKeyStroke("released ENTER"), "released");
public UIDefaults getDefaults() {
final UIDefaults defaults = base.getDefaults();
final Theme currentTheme = LafManager.getTheme();
for (DefaultsInitTask task : INIT_TASKS) {
task.run(currentTheme, defaults);
}
return defaults;
}
private void loadThemeDefaults(final Theme currentTheme, final UIDefaults defaults) {
Properties uiProps = new Properties();
currentTheme.loadDefaults(uiProps, defaults);
//Load overwrites the user has set.
PropertyLoader.putProperties(LafManager.getUserProperties(), uiProps, defaults);
currentTheme.loadGlobals(uiProps, defaults);
installGlobals(uiProps, defaults);
loadFontProperties(uiProps, defaults);
currentTheme.loadUIProperties(uiProps, defaults);
currentTheme.loadIconProperties(uiProps, defaults);
Decorations.loadDecorationProperties(uiProps, defaults);
currentTheme.loadPlatformProperties(uiProps, defaults);
adjustPlatformSpecifics(uiProps);
loadSystemOverwrites(uiProps, defaults);
defaults.putAll(uiProps);
StyleSheet styleSheet = currentTheme.loadStyleSheet();
new HTMLEditorKit().setStyleSheet(styleSheet);
}
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);
}
private void loadSystemOverwrites(final Properties uiProps, final UIDefaults defaults) {
Properties overwrites = PropertyLoader.loadProperties(DarkLaf.class, "overwrites", "properties/");
overwrites.values().removeIf(v -> System.getProperty(SYSTEM_PROPERTY_PREFIX + v.toString()) == null);
overwrites.entrySet().forEach(
e -> e.setValue(System.getProperty(SYSTEM_PROPERTY_PREFIX + e.getValue().toString())));
PropertyLoader.putProperties(overwrites, uiProps, defaults);
}
@SuppressWarnings({"HardCodedStringLiteral"})
private void initIdeaDefaults(final UIDefaults defaults) {
defaults.put("Table.ancestorInputMap", new UIDefaults.LazyInputMap(
new Object[]{
"ctrl C", "copy",
"meta C", "copy",
"ctrl V", "paste",
"meta V", "paste",
"ctrl X", "cut",
"meta X", "cut",
"COPY", "copy",
"PASTE", "paste",
"CUT", "cut",
"control INSERT", "copy",
"shift INSERT", "paste",
"shift DELETE", "cut",
"RIGHT", "selectNextColumn",
"KP_RIGHT", "selectNextColumn",
"LEFT", "selectPreviousColumn",
"KP_LEFT", "selectPreviousColumn",
"DOWN", "selectNextRow",
"KP_DOWN", "selectNextRow",
"UP", "selectPreviousRow",
"KP_UP", "selectPreviousRow",
"shift RIGHT", "selectNextColumnExtendSelection",
"shift KP_RIGHT", "selectNextColumnExtendSelection",
"shift LEFT", "selectPreviousColumnExtendSelection",
"shift KP_LEFT", "selectPreviousColumnExtendSelection",
"shift DOWN", "selectNextRowExtendSelection",
"shift KP_DOWN", "selectNextRowExtendSelection",
"shift UP", "selectPreviousRowExtendSelection",
"shift KP_UP", "selectPreviousRowExtendSelection",
"PAGE_UP", "scrollUpChangeSelection",
"PAGE_DOWN", "scrollDownChangeSelection",
"HOME", "selectFirstColumn",
"END", "selectLastColumn",
"shift PAGE_UP", "scrollUpExtendSelection",
"shift PAGE_DOWN", "scrollDownExtendSelection",
"shift HOME", "selectFirstColumnExtendSelection",
"shift END", "selectLastColumnExtendSelection",
"ctrl PAGE_UP", "scrollLeftChangeSelection",
"ctrl PAGE_DOWN", "scrollRightChangeSelection",
"ctrl HOME", "selectFirstRow",
"ctrl END", "selectLastRow",
"ctrl shift PAGE_UP", "scrollRightExtendSelection",
"ctrl shift PAGE_DOWN", "scrollLeftExtendSelection",
"ctrl shift HOME", "selectFirstRowExtendSelection",
"ctrl shift END", "selectLastRowExtendSelection",
"TAB", "selectNextColumnCell",
"shift TAB", "selectPreviousColumnCell",
"ENTER", "selectNextRowCell",
"shift ENTER", "selectPreviousRowCell",
"ctrl A", "selectAll",
"meta A", "selectAll",
"ESCAPE", "cancel",
"F2", "startEditing"
}));
@Override
public String getName() {
return "Darklaf";
}
@ -346,74 +142,12 @@ public class DarkLaf extends BasicLookAndFeel {
return getName();
}
private static void patchComboBox(final UIDefaults metalDefaults, final UIDefaults defaults) {
defaults.remove("ComboBox.ancestorInputMap");
defaults.remove("ComboBox.actionMap");
defaults.put("ComboBox.ancestorInputMap", metalDefaults.get("ComboBox.ancestorInputMap"));
defaults.put("ComboBox.actionMap", metalDefaults.get("ComboBox.actionMap"));
}
private static void installCutCopyPasteShortcuts(final InputMap inputMap,
final boolean useSimpleActionKeys) {
final String copyActionKey = useSimpleActionKeys ? "copy" : DefaultEditorKit.copyAction;
final String pasteActionKey = useSimpleActionKeys ? "paste" : DefaultEditorKit.pasteAction;
final String cutActionKey = useSimpleActionKeys ? "cut" : DefaultEditorKit.cutAction;
final int mask = SystemInfo.isMac ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK;
// Ctrl+Ins, Shift+Ins, Shift+Del
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, InputEvent.CTRL_DOWN_MASK), copyActionKey);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, InputEvent.SHIFT_DOWN_MASK), pasteActionKey);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, InputEvent.SHIFT_DOWN_MASK), cutActionKey);
// Ctrl+C, Ctrl+V, Ctrl+X
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, mask), copyActionKey);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, mask), pasteActionKey);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, mask), DefaultEditorKit.cutAction);
}
private void installGlobals(final Properties uiProps, final UIDefaults defaults) {
final HashMap<String, Object> globalSettings = new HashMap<>();
final String prefix = "global.";
for (final Object key : uiProps.keySet()) {
if (key instanceof String && ((String) key).startsWith(prefix)) {
globalSettings.put(((String) key).substring(prefix.length()), uiProps.get(key));
}
}
for (final Object key : defaults.keySet()) {
if (key instanceof String && ((String) key).contains(".")) {
final String s = (String) key;
final String globalKey = s.substring(s.lastIndexOf('.') + 1);
if (globalSettings.containsKey(globalKey)) {
defaults.put(key, globalSettings.get(globalKey));
}
}
}
}
@Override
public String getDescription() {
return "Dark Look and feel based on Darcula-LAF";
}
@Override
public void initialize() {
/*
* On macOS the default PopupFactory is overwritten with a custom one, which always uses heavyweight popups.
* This is disadvantageous for the behaviour of custom tooltips.
*/
base.initialize();
PopupFactory.setSharedInstance(new DarkPopupFactory());
}
@Override
public void uninitialize() {
base.uninitialize();
DarkPopupMenuUI.MouseGrabber mouseGrabber = DarkPopupMenuUI.getMouseGrabber();
if (mouseGrabber != null) {
mouseGrabber.uninstall();
}
}
@Override
public boolean isNativeLookAndFeel() {
return true;
@ -428,5 +162,4 @@ public class DarkLaf extends BasicLookAndFeel {
public boolean getSupportsWindowDecorations() {
return Decorations.isCustomDecorationSupported();
}
}

62
core/src/main/java/com/github/weisj/darklaf/LafManager.java

@ -25,6 +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.task.DefaultsInitTask;
import com.github.weisj.darklaf.theme.*;
import javax.swing.*;
@ -32,7 +33,8 @@ import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;
import java.util.Collection;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
@ -48,7 +50,7 @@ public final class LafManager {
private static Theme theme;
private static boolean logEnabled = false;
private static boolean decorationsOverwrite = true;
private static final Properties properties = new Properties();
private static final Collection<DefaultsInitTask> uiDefaultsTasks = new HashSet<>();
static {
enableLogging(true);
@ -240,60 +242,30 @@ public final class LafManager {
}
/**
* Set a custom property.
* <p>
* Note: These properties are loaded after {@link Theme#loadDefaults(Properties, UIDefaults)} and should only be
* used to overwrite the values specified in `[theme]_defaults.properties`.
* Register a task to modify the ui defaults.
*
* @param key the key.
* @param value the value.
* @param task the defaults init task.
*/
public static void setProperty(final String key, final String value) {
properties.setProperty(key, value);
public static void registerDefaultsInitTask(final DefaultsInitTask task) {
uiDefaultsTasks.add(task);
}
/**
* Remove a custom property.
* <p>
* Note: These properties are loaded after {@link Theme#loadDefaults(Properties, UIDefaults)} and should only be
* used to overwrite the values specified in `[theme]_defaults.properties`.
* Remove a registered task to modify the ui defaults.
*
* @param key the key.
* @param task the defaults init task.
*/
public static void removeProperty(final String key) {
properties.remove(key);
public static void removeDefaultsInitTask(final DefaultsInitTask task) {
uiDefaultsTasks.remove(task);
}
/**
* Remove all custom properties.
* <p>
* Note: These properties are loaded after {@link Theme#loadDefaults(Properties, UIDefaults)} and should only be
* used to overwrite the values specified in `[theme]_defaults.properties`.
*/
public static void clearProperties() {
properties.clear();
}
/**
* Get the custom properties.
* <p>
* Note: These properties are loaded after {@link Theme#loadDefaults(Properties, UIDefaults)} and should only be
* used to overwrite the values specified in `[theme]_defaults.properties`.
*/
public static Properties getUserProperties() {
return properties;
}
/**
* Remove a custom property.
* <p>
* Note: These properties are loaded after {@link Theme#loadDefaults(Properties, UIDefaults)} and should only be
* used to overwrite the values specified in `[theme]_defaults.properties`.
* Get a view of all currently registered init tasks. Modification will also mutate the collection itself.
*
* @param key the key.
* @return the value associated with `key`.
* @return collection of init tasks.
*/
public String getProperty(final String key) {
return properties.getProperty(key);
public static Collection<DefaultsInitTask> getUserInitTasks() {
return uiDefaultsTasks;
}
}

11
core/src/main/java/com/github/weisj/darklaf/components/border/DarkBorders.java

@ -63,16 +63,21 @@ public final class DarkBorders {
return createBorder(top, left, bottom, right, lineWidgetBorderMap, "borderSecondary");
}
public static void update(final UIDefaults defaults) {
Color borderColor = defaults.getColor("border");
public static void update(final Map<Object, Object> defaults) {
Color borderColor = getColor(defaults, "border");
for (WeakReference<WeakLineBorder> border : lineBorderMap.values()) {
WeakLineBorder b = border.get();
if (b != null) b.setColor(borderColor);
}
Color borderSecondaryColor = defaults.getColor("borderSecondary");
Color borderSecondaryColor = getColor(defaults, "borderSecondary");
for (WeakReference<WeakLineBorder> border : lineWidgetBorderMap.values()) {
WeakLineBorder b = border.get();
if (b != null) b.setColor(borderSecondaryColor);
}
}
private static Color getColor(final Map<Object, Object> defaults, final String key) {
Object color = defaults.get(key);
return color instanceof Color ? (Color) color : null;
}
}

3
core/src/main/java/com/github/weisj/darklaf/platform/Decorations.java

@ -34,6 +34,7 @@ import com.github.weisj.darklaf.util.SystemInfo;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import java.util.Properties;
public final class Decorations {
@ -83,7 +84,7 @@ public final class Decorations {
decorationsProvider.initialize();
}
public static void loadDecorationProperties(final Properties uiProps, final UIDefaults defaults) {
public static void loadDecorationProperties(final Properties uiProps, final Map<Object, Object> defaults) {
decorationsProvider.loadDecorationProperties(uiProps, defaults);
}
}

3
core/src/main/java/com/github/weisj/darklaf/platform/DefaultDecorationsProvider.java

@ -28,6 +28,7 @@ import com.github.weisj.darklaf.decorations.DecorationsProvider;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import java.util.Properties;
public class DefaultDecorationsProvider implements DecorationsProvider {
@ -59,6 +60,6 @@ public class DefaultDecorationsProvider implements DecorationsProvider {
}
@Override
public void loadDecorationProperties(final Properties properties, final UIDefaults currentDefaults) {
public void loadDecorationProperties(final Properties properties, final Map<Object, Object> currentDefaults) {
}
}

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

@ -0,0 +1,33 @@
/*
* 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.task;
import com.github.weisj.darklaf.theme.Theme;
import java.util.Map;
public interface DefaultsInitTask {
void run(final Theme currentTheme, final Map<Object, Object> defaults);
}

114
core/src/main/java/com/github/weisj/darklaf/task/FontDefaultsInitTask.java

@ -0,0 +1,114 @@
/*
* 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.task;
import com.github.weisj.darklaf.DarkLaf;
import com.github.weisj.darklaf.PropertyLoader;
import com.github.weisj.darklaf.theme.FontMapper;
import com.github.weisj.darklaf.theme.FontSizeRule;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.util.SystemInfo;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.UIResource;
import java.awt.*;
import java.awt.font.TextAttribute;
import java.text.AttributedCharacterIterator;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
public class FontDefaultsInitTask implements DefaultsInitTask {
private static final String FONT_PROPERTY_PATH = "properties/";
private static final String FONT_SIZE_DEFAULTS_NAME = "font_sizes";
private static final String FONT_DEFAULTS_NAME = "font_sizes";
private static final String MAC_OS_CATALINA_FONT_NAME = ".AppleSystemUIFont";
private static final String MAC_OS_FONT_NAME = ".SF NS Text";
@Override
public void run(final Theme currentTheme, final Map<Object, Object> defaults) {
loadFontProperties(defaults);
if (SystemInfo.isMac) {
patchMacOSFonts(defaults);
}
applyFontRule(currentTheme, defaults);
}
private void loadFontProperties(final Map<Object, Object> defaults) {
Properties fontSizeProps = PropertyLoader.loadProperties(DarkLaf.class,
FONT_SIZE_DEFAULTS_NAME,
FONT_PROPERTY_PATH);
PropertyLoader.putProperties(fontSizeProps, defaults);
Properties fontProps = PropertyLoader.loadProperties(DarkLaf.class,
FONT_DEFAULTS_NAME,
FONT_PROPERTY_PATH);
PropertyLoader.putProperties(fontProps, defaults);
}
private void patchMacOSFonts(final Map<Object, Object> defaults) {
for (Map.Entry<Object, Object> entry : defaults.entrySet()) {
if (entry.getValue() instanceof Font) {
Font font = (Font) entry.getValue();
entry.setValue(macOSFontFromFont(font));
}
}
}
private Font macOSFontFromFont(final Font font) {
Map<AttributedCharacterIterator.Attribute, Integer> attributes
= Collections.singletonMap(TextAttribute.KERNING, TextAttribute.KERNING_ON);
String fontName = SystemInfo.isMacOSCatalina ? MAC_OS_CATALINA_FONT_NAME : MAC_OS_FONT_NAME;
Font macFont = new Font(fontName, font.getStyle(), font.getSize()).deriveFont(attributes);
if (font instanceof UIResource) {
macFont = new FontUIResource(macFont);
}
return macFont == null ? font : macFont;
}
private void applyFontRule(final Theme currentTheme, final Map<Object, Object> 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(), rule, defaults));
}
}
}
private Font fontWithRule(final Font font, final FontSizeRule rule, final Map<Object, Object> defaults) {
Font withRule = getFontMapper(rule).map(font, defaults);
if (font instanceof UIResource
&& !(withRule instanceof UIResource)) {
withRule = new FontUIResource(withRule);
}
return withRule;
}
private FontMapper getFontMapper(final FontSizeRule rule) {
if (rule == null) return (font, defaults) -> font;
return rule.getFontMapper();
}
}

95
core/src/main/java/com/github/weisj/darklaf/task/IdeaDefaultsInitTask.java

@ -0,0 +1,95 @@
/*
* 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.task;
import com.github.weisj.darklaf.theme.Theme;
import javax.swing.*;
import java.util.Map;
public class IdeaDefaultsInitTask implements DefaultsInitTask {
@Override
public void run(final Theme currentTheme, final Map<Object, Object> defaults) {
initIdeaDefaults(defaults);
}
@SuppressWarnings({"HardCodedStringLiteral"})
private void initIdeaDefaults(final Map<Object, Object> defaults) {
defaults.put("Table.ancestorInputMap", new UIDefaults.LazyInputMap(
new Object[]{
"ctrl C", "copy",
"meta C", "copy",
"ctrl V", "paste",
"meta V", "paste",
"ctrl X", "cut",
"meta X", "cut",
"COPY", "copy",
"PASTE", "paste",
"CUT", "cut",
"control INSERT", "copy",
"shift INSERT", "paste",
"shift DELETE", "cut",
"RIGHT", "selectNextColumn",
"KP_RIGHT", "selectNextColumn",
"LEFT", "selectPreviousColumn",
"KP_LEFT", "selectPreviousColumn",
"DOWN", "selectNextRow",
"KP_DOWN", "selectNextRow",
"UP", "selectPreviousRow",
"KP_UP", "selectPreviousRow",
"shift RIGHT", "selectNextColumnExtendSelection",
"shift KP_RIGHT", "selectNextColumnExtendSelection",
"shift LEFT", "selectPreviousColumnExtendSelection",
"shift KP_LEFT", "selectPreviousColumnExtendSelection",
"shift DOWN", "selectNextRowExtendSelection",
"shift KP_DOWN", "selectNextRowExtendSelection",
"shift UP", "selectPreviousRowExtendSelection",
"shift KP_UP", "selectPreviousRowExtendSelection",
"PAGE_UP", "scrollUpChangeSelection",
"PAGE_DOWN", "scrollDownChangeSelection",
"HOME", "selectFirstColumn",
"END", "selectLastColumn",
"shift PAGE_UP", "scrollUpExtendSelection",
"shift PAGE_DOWN", "scrollDownExtendSelection",
"shift HOME", "selectFirstColumnExtendSelection",
"shift END", "selectLastColumnExtendSelection",
"ctrl PAGE_UP", "scrollLeftChangeSelection",
"ctrl PAGE_DOWN", "scrollRightChangeSelection",
"ctrl HOME", "selectFirstRow",
"ctrl END", "selectLastRow",
"ctrl shift PAGE_UP", "scrollRightExtendSelection",
"ctrl shift PAGE_DOWN", "scrollLeftExtendSelection",
"ctrl shift HOME", "selectFirstRowExtendSelection",
"ctrl shift END", "selectLastRowExtendSelection",
"TAB", "selectNextColumnCell",
"shift TAB", "selectPreviousColumnCell",
"ENTER", "selectNextRowCell",
"shift ENTER", "selectPreviousRowCell",
"ctrl A", "selectAll",
"meta A", "selectAll",
"ESCAPE", "cancel",
"F2", "startEditing"
}));
}
}

108
core/src/main/java/com/github/weisj/darklaf/task/InputDefaultsInitTask.java

@ -0,0 +1,108 @@
/*
* 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.task;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.util.SystemInfo;
import javax.swing.*;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.text.DefaultEditorKit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Map;
public class InputDefaultsInitTask implements DefaultsInitTask {
@Override
public void run(final Theme currentTheme, final Map<Object, Object> defaults) {
initInputMapDefaults(defaults);
patchComboBox(new MetalLookAndFeel().getDefaults(), defaults);
}
private void initInputMapDefaults(final Map<Object, Object> defaults) {
// Make ENTER work in JTrees
final InputMap treeInputMap = (InputMap) defaults.get("Tree.focusInputMap");
if (treeInputMap != null) {
// it's really possible. For example, GTK+ doesn't have such map
treeInputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "toggle");
}
// Cut/Copy/Paste in JTextAreas
final InputMap textAreaInputMap = (InputMap) defaults.get("TextArea.focusInputMap");
if (textAreaInputMap != null) {
// It really can be null, for example when LAF isn't properly initialized
// (Alloy license problem)
installCutCopyPasteShortcuts(textAreaInputMap, false);
}
// Cut/Copy/Paste in JTextFields
final InputMap textFieldInputMap = (InputMap) defaults.get("TextField.focusInputMap");
if (textFieldInputMap != null) {
// It really can be null, for example when LAF isn't properly initialized
// (Alloy license problem)
installCutCopyPasteShortcuts(textFieldInputMap, false);
}
// Cut/Copy/Paste in JPasswordField
final InputMap passwordFieldInputMap = (InputMap) defaults.get("PasswordField.focusInputMap");
if (passwordFieldInputMap != null) {
// It really can be null, for example when LAF isn't properly initialized
// (Alloy license problem)
installCutCopyPasteShortcuts(passwordFieldInputMap, false);
}
// Cut/Copy/Paste in JTables
final InputMap tableInputMap = (InputMap) defaults.get("Table.ancestorInputMap");
if (tableInputMap != null) {
// It really can be null, for example when LAF isn't properly initialized
// (Alloy license problem)
installCutCopyPasteShortcuts(tableInputMap, true);
}
final InputMap buttonInputMap = (InputMap) defaults.get("Button.focusInputMap");
if (buttonInputMap != null && !SystemInfo.isMac) {
buttonInputMap.put(KeyStroke.getKeyStroke("ENTER"), "pressed");
buttonInputMap.put(KeyStroke.getKeyStroke("released ENTER"), "released");
}
}
private void installCutCopyPasteShortcuts(final InputMap inputMap,
final boolean useSimpleActionKeys) {
final String copyActionKey = useSimpleActionKeys ? "copy" : DefaultEditorKit.copyAction;
final String pasteActionKey = useSimpleActionKeys ? "paste" : DefaultEditorKit.pasteAction;
final String cutActionKey = useSimpleActionKeys ? "cut" : DefaultEditorKit.cutAction;
final int mask = SystemInfo.isMac ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK;
// Ctrl+Ins, Shift+Ins, Shift+Del
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, InputEvent.CTRL_DOWN_MASK), copyActionKey);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, InputEvent.SHIFT_DOWN_MASK), pasteActionKey);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, InputEvent.SHIFT_DOWN_MASK), cutActionKey);
// Ctrl+C, Ctrl+V, Ctrl+X
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_C, mask), copyActionKey);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, mask), pasteActionKey);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, mask), DefaultEditorKit.cutAction);
}
private static void patchComboBox(final UIDefaults metalDefaults, final Map<Object, Object> defaults) {
defaults.remove("ComboBox.ancestorInputMap");
defaults.remove("ComboBox.actionMap");
defaults.put("ComboBox.ancestorInputMap", metalDefaults.get("ComboBox.ancestorInputMap"));
defaults.put("ComboBox.actionMap", metalDefaults.get("ComboBox.actionMap"));
}
}

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

@ -0,0 +1,44 @@
/*
* 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.task;
import com.github.weisj.darklaf.platform.Decorations;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.ui.popupmenu.DarkPopupMenuUI;
import com.github.weisj.darklaf.util.SystemInfo;
import javax.swing.*;
import java.util.Map;
public class PlatformDefaultsInitTask implements DefaultsInitTask {
@Override
public void run(final Theme currentTheme, final Map<Object, Object> defaults) {
String key = DarkPopupMenuUI.KEY_DEFAULT_LIGHTWEIGHT_POPUPS;
if (SystemInfo.isWindows10 && Decorations.isCustomDecorationSupported()) {
JPopupMenu.setDefaultLightWeightPopupEnabled(Boolean.TRUE.equals(defaults.get(key + ".windows")));
} else {
JPopupMenu.setDefaultLightWeightPopupEnabled(Boolean.TRUE.equals(defaults.get(key)));
}
}
}

50
core/src/main/java/com/github/weisj/darklaf/task/SystemDefaultsInitTask.java

@ -0,0 +1,50 @@
/*
* 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.task;
import com.github.weisj.darklaf.DarkLaf;
import com.github.weisj.darklaf.PropertyLoader;
import com.github.weisj.darklaf.theme.Theme;
import java.util.Map;
import java.util.Properties;
public class SystemDefaultsInitTask implements DefaultsInitTask {
private static final String OVERWRITES_PATH = "properties/";
private static final String OVERWRITES_NAME = "overwrites";
@Override
public void run(final Theme currentTheme, final Map<Object, Object> defaults) {
loadSystemOverwrites(defaults);
}
private void loadSystemOverwrites(final Map<Object, Object> defaults) {
Properties overwrites = PropertyLoader.loadProperties(DarkLaf.class, OVERWRITES_NAME, OVERWRITES_PATH);
overwrites.values().removeIf(v -> System.getProperty(DarkLaf.SYSTEM_PROPERTY_PREFIX + v.toString()) == null);
overwrites.entrySet().forEach(
e -> e.setValue(System.getProperty(DarkLaf.SYSTEM_PROPERTY_PREFIX + e.getValue().toString())));
PropertyLoader.putProperties(overwrites, defaults);
}
}

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

@ -0,0 +1,99 @@
/*
* 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.task;
import com.github.weisj.darklaf.platform.Decorations;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.util.SystemInfo;
import javax.swing.*;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class ThemeDefaultsInitTask implements DefaultsInitTask {
private static final String GLOBAL_PREFIX = "global.";
private static final String MAC_OS_MENU_BAR_KEY = "apple.laf.useScreenMenuBar";
private final DefaultsInitTask userPreferenceInitTask = new UserPreferenceInitTask();
@Override
public void run(final Theme currentTheme, final Map<Object, Object> defaults) {
if (!(defaults instanceof UIDefaults)) return;
loadThemeDefaults(currentTheme, (UIDefaults) defaults);
}
private void loadThemeDefaults(final Theme currentTheme, final UIDefaults defaults) {
Properties uiProps = new Properties();
currentTheme.loadDefaults(uiProps, defaults);
/*
* User preferences need to be applied here so changes are applied to all
* components that use the property.
*/
userPreferenceInitTask.run(currentTheme, uiProps);
currentTheme.loadGlobals(uiProps, defaults);
installGlobals(uiProps, defaults);
currentTheme.loadUIProperties(uiProps, defaults);
currentTheme.loadIconProperties(uiProps, defaults);
Decorations.loadDecorationProperties(uiProps, defaults);
currentTheme.loadPlatformProperties(uiProps, defaults);
adjustPlatformSpecifics(uiProps);
defaults.putAll(uiProps);
StyleSheet styleSheet = currentTheme.loadStyleSheet();
new HTMLEditorKit().setStyleSheet(styleSheet);
}
private void installGlobals(final Properties uiProps, final Map<Object, Object> defaults) {
final HashMap<String, Object> globalSettings = new HashMap<>();
for (final Object key : uiProps.keySet()) {
if (key instanceof String && ((String) key).startsWith(GLOBAL_PREFIX)) {
globalSettings.put(((String) key).substring(GLOBAL_PREFIX.length()), uiProps.get(key));
}
}
for (final Object key : defaults.keySet()) {
if (key instanceof String && ((String) key).contains(".")) {
final String s = (String) key;
final String globalKey = s.substring(s.lastIndexOf('.') + 1);
if (globalSettings.containsKey(globalKey)) {
defaults.put(key, globalSettings.get(globalKey));
}
}
}
}
protected void adjustPlatformSpecifics(final Properties uiProps) {
boolean useScreenMenuBar = Boolean.getBoolean(MAC_OS_MENU_BAR_KEY);
// If user wants to use Apple menu bar, then we need to keep the default
// component for MenuBarUI and MenuUI
if (SystemInfo.isMac && useScreenMenuBar) {
uiProps.remove("MenuBarUI");
}
}
}

39
core/src/main/java/com/github/weisj/darklaf/task/UserPreferenceInitTask.java

@ -0,0 +1,39 @@
/*
* 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.task;
import com.github.weisj.darklaf.LafManager;
import com.github.weisj.darklaf.theme.Theme;
import java.util.Map;
public class UserPreferenceInitTask implements DefaultsInitTask {
@Override
public void run(final Theme currentTheme, final Map<Object, Object> defaults) {
for (DefaultsInitTask task : LafManager.getUserInitTasks()) {
if (task != null) task.run(currentTheme, defaults);
}
}
}

50
core/src/main/java/com/github/weisj/darklaf/task/UtilityDefaultsInitTask.java

@ -0,0 +1,50 @@
/*
* 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.task;
import com.github.weisj.darklaf.components.border.DarkBorders;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.util.DarkUIUtil;
import java.util.Map;
public class UtilityDefaultsInitTask implements DefaultsInitTask {
@Override
public void run(final Theme currentTheme, final Map<Object, Object> defaults) {
setupUtils(defaults);
}
private void setupUtils(final Map<Object, Object> defaults) {
DarkUIUtil.setDropOpacity(getOpacity(defaults, "dropOpacity"));
DarkUIUtil.setGlowOpacity(getOpacity(defaults, "glowOpacity"));
DarkUIUtil.setShadowOpacity(getOpacity(defaults, "shadowOpacity"));
DarkBorders.update(defaults);
}
private float getOpacity(final Map<Object, Object> defaults, final String key) {
Object obj = defaults.get(key);
int val = (obj instanceof Integer) ? (int) obj : 100;
return val / 100f;
}
}

4
core/src/main/java/com/github/weisj/darklaf/theme/FontMapper.java

@ -23,10 +23,10 @@
*/
package com.github.weisj.darklaf.theme;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
public interface FontMapper {
Font map(final Font font, final UIDefaults defaults);
Font map(final Font font, final Map<Object, Object> defaults);
}

6
core/src/main/java/com/github/weisj/darklaf/theme/PropertyFontMapper.java

@ -25,8 +25,8 @@ package com.github.weisj.darklaf.theme;
import com.github.weisj.darklaf.LafManager;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import java.util.logging.Logger;
public class PropertyFontMapper implements FontMapper {
@ -42,7 +42,7 @@ public class PropertyFontMapper implements FontMapper {
}
@Override
public Font map(final Font font, final UIDefaults defaults) {
public Font map(final Font font, final Map<Object, Object> defaults) {
adjustment = getSize(defaults);
// No need to create a new font.
if (adjustment == 0) return font;
@ -56,7 +56,7 @@ public class PropertyFontMapper implements FontMapper {
return font.deriveFont(font.getSize2D() + adjustment);
}
private int getSize(final UIDefaults defaults) {
private int getSize(final Map<Object, Object> defaults) {
// Use cached value if already queried.
if (lastTheme == LafManager.getTheme()) return adjustment;
lastTheme = LafManager.getTheme();

12
core/src/main/java/com/github/weisj/darklaf/theme/Theme.java

@ -368,16 +368,4 @@ public abstract class Theme {
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();
}
}

3
decorations-base/src/main/java/com/github/weisj/darklaf/decorations/DecorationsProvider.java

@ -25,6 +25,7 @@ package com.github.weisj.darklaf.decorations;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import java.util.Properties;
public interface DecorationsProvider {
@ -58,7 +59,7 @@ public interface DecorationsProvider {
* @param properties the properties to load the values into.
* @param currentDefaults the current ui defaults.
*/
void loadDecorationProperties(Properties properties, UIDefaults currentDefaults);
void loadDecorationProperties(Properties properties, Map<Object, Object> currentDefaults);
/**
* Initialize the window of a popup menu.

3
macos/src/main/java/com/github/weisj/darklaf/platform/macos/MacOSDecorationsProvider.java

@ -31,6 +31,7 @@ import com.github.weisj.darklaf.platform.macos.ui.MacOSTitlePane;
import javax.swing.*;
import java.awt.*;
import java.util.Map;
import java.util.Properties;
public class MacOSDecorationsProvider implements DecorationsProvider {
@ -51,7 +52,7 @@ public class MacOSDecorationsProvider implements DecorationsProvider {
}
@Override
public void loadDecorationProperties(final Properties properties, final UIDefaults currentDefaults) {
public void loadDecorationProperties(final Properties properties, final Map<Object, Object> currentDefaults) {
IconLoader iconLoader = IconLoader.get(MacOSDecorationsProvider.class);
PropertyLoader.putProperties(PropertyLoader.loadProperties(MacOSDecorationsProvider.class,
"macos_decorations", ""),

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

@ -98,14 +98,29 @@ public final class PropertyLoader {
}
public static void putProperties(final Properties properties, final Properties accumulator,
final UIDefaults currentDefaults) {
final Map<Object, Object> currentDefaults) {
putProperties(properties, accumulator, currentDefaults, ICON_LOADER);
}
public static void putProperties(final Properties properties, final Properties accumulator,
final UIDefaults currentDefaults, final IconLoader iconLoader) {
for (final String key : properties.stringPropertyNames()) {
final String value = properties.getProperty(key);
final Map<Object, Object> currentDefaults, final IconLoader iconLoader) {
putProperties(properties, properties.stringPropertyNames(), accumulator, currentDefaults, iconLoader);
}
public static void putProperties(final Properties properties, final Map<Object, Object> defaults) {
putProperties(properties, defaults, ICON_LOADER);
}
public static void putProperties(final Properties properties, final Map<Object, Object> defaults,
final IconLoader iconLoader) {
putProperties(properties, properties.stringPropertyNames(), defaults, defaults, iconLoader);
}
public static void putProperties(final Map<Object, Object> properties, final Set<String> keys,
final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults, final IconLoader iconLoader) {
for (final String key : keys) {
final String value = properties.get(key).toString();
Object parsed = parseValue(key, value, accumulator, currentDefaults, iconLoader);
if (parsed != null) {
accumulator.put(parseKey(key), parsed);
@ -115,11 +130,6 @@ public final class PropertyLoader {
}
}
private static Object parseValue(final String key, final String value, final Properties accumulator,
final UIDefaults currentDefaults, final IconLoader iconLoader) {
return parseValue(key, value, false, accumulator, currentDefaults, iconLoader);
}
private static String parseKey(final String key) {
if (addReferenceInfo) return key;
return key.startsWith(String.valueOf(REFERENCE_PREFIX)) ? key.substring(1) : key;
@ -127,13 +137,13 @@ public final class PropertyLoader {
private static Object parseValue(final String propertyKey, final String value,
final boolean ignoreRequest, final Map<Object, Object> accumulator,
final UIDefaults currentDefaults, final IconLoader iconLoader) {
final Map<Object, Object> accumulator,
final Map<Object, Object> currentDefaults, final IconLoader iconLoader) {
if (PropertyValue.NULL.equals(value)) {
return null;
}
String key = propertyKey;
boolean skipObjects = ignoreRequest;
boolean skipObjects = false;
if (key.startsWith(String.valueOf(REFERENCE_PREFIX))) {
key = parseKey(key);
skipObjects = true;
@ -209,7 +219,7 @@ public final class PropertyLoader {
@SuppressWarnings("MagicConstant")
private static Object parseFont(final String key, final String value, final Map<Object, Object> accumulator,
final UIDefaults currentDefaults) {
final Map<Object, Object> currentDefaults) {
String val = value;
Font base = null;
int size = -1;
@ -233,7 +243,7 @@ public final class PropertyLoader {
}
if (base == null) base = parseExplicitFont(value);
if (base == null && accumulator.get(key) instanceof Font) base = (Font) accumulator.get(key);
if (base == null) base = currentDefaults.getFont(key);
if (base == null && currentDefaults.get(key) instanceof Font) base = (Font) currentDefaults.get(key);
if (base == null) base = new Font("Dialog", Font.PLAIN, 12);
if (size > 0) base = base.deriveFont((float) size);
if (style >= 0) base = base.deriveFont(style);
@ -278,14 +288,14 @@ public final class PropertyLoader {
private static Pair<Font, String> parseFrom(final String val,
final Map<Object, Object> accumulator,
final UIDefaults currentDefaults) {
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 = null;
if (accumulator.get(key) instanceof Font) font = (Font) accumulator.get(key);
if (font == null) font = currentDefaults.getFont(key);
if (font == null && currentDefaults.get(key) instanceof Font) font = (Font) currentDefaults.get(key);
return new Pair<>(font, rest);
}

3
windows/src/main/java/com/github/weisj/darklaf/platform/windows/WindowsDecorationsProvider.java

@ -34,6 +34,7 @@ import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Map;
import java.util.Properties;
public class WindowsDecorationsProvider implements DecorationsProvider {
@ -82,7 +83,7 @@ public class WindowsDecorationsProvider implements DecorationsProvider {
}
@Override
public void loadDecorationProperties(final Properties properties, final UIDefaults currentDefaults) {
public void loadDecorationProperties(final Properties properties, final Map<Object, Object> currentDefaults) {
IconLoader iconLoader = IconLoader.get(WindowsDecorationsProvider.class);
PropertyLoader.putProperties(PropertyLoader.loadProperties(WindowsDecorationsProvider.class,
"windows_decorations", ""),

Loading…
Cancel
Save