Browse Source

Decouple settings panel from ThemeSettings

Reduce amount of times ColoredRadioButton patches the underlying icon.
Ensure color returned by ForegroundColorGenerationTask is an UIResource.
Improve ForegroundColorGenerationTask to account for saturation of color.
pull/189/head
weisj 4 years ago
parent
commit
6ff0ffc799
  1. 123
      core/src/main/java/com/github/weisj/darklaf/components/ColoredRadioButton.java
  2. 2
      core/src/main/java/com/github/weisj/darklaf/graphics/StringPainter.java
  3. 39
      core/src/main/java/com/github/weisj/darklaf/settings/DefaultSettingsConfiguration.java
  4. 255
      core/src/main/java/com/github/weisj/darklaf/settings/SettingsConfiguration.java
  5. 133
      core/src/main/java/com/github/weisj/darklaf/settings/ThemeSettings.java
  6. 496
      core/src/main/java/com/github/weisj/darklaf/settings/ThemeSettingsPanel.java
  7. 62
      core/src/main/java/com/github/weisj/darklaf/task/ForegroundColorGenerationTask.java
  8. 2
      core/src/main/java/javax/swing/text/DefaultHighlighterDark/DarkHighlightPainter.java
  9. 3
      core/src/test/java/ui/SettingsDemo.java
  10. 14
      utils/src/main/java/com/github/weisj/darklaf/util/ColorUtil.java
  11. 14
      utils/src/main/java/com/github/weisj/darklaf/util/LazyValue.java

123
core/src/main/java/com/github/weisj/darklaf/components/ColoredRadioButton.java

@ -28,7 +28,7 @@ import java.awt.*;
import java.util.Properties;
import javax.swing.*;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI;
import com.github.weisj.darklaf.DarkLaf;
import com.github.weisj.darklaf.LafManager;
@ -36,6 +36,7 @@ import com.github.weisj.darklaf.PropertyLoader;
import com.github.weisj.darklaf.icons.IconLoader;
import com.github.weisj.darklaf.icons.StateIcon;
import com.github.weisj.darklaf.task.AccentColorAdjustmentTask;
import com.github.weisj.darklaf.task.ForegroundColorGenerationTask;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.ui.togglebutton.radiobutton.DarkRadioButtonUI;
import com.github.weisj.darklaf.util.DarkUIUtil;
@ -44,39 +45,70 @@ public class ColoredRadioButton extends JRadioButton {
public static final Color DEFAULT_FILLED = new Color(0);
private Color color;
private Color focusColor;
public ColoredRadioButton(final String text, final Color color) {
super(text, null, false);
setColor(color);
setColors(color, color);
}
public ColoredRadioButton(final String text, final boolean selected, final Color color) {
super(text, null, selected);
setColor(color);
setColors(color, color);
}
public ColoredRadioButton(final String text, final Color color, final Color focusColor) {
super(text, null, false);
setColors(color, focusColor);
}
public ColoredRadioButton(final String text, final boolean selected, final Color color, final Color focusColor) {
super(text, null, selected);
setColors(color, focusColor);
}
public void setColors(final Color color, final Color focusColor) {
this.color = color;
this.focusColor = focusColor != null ? focusColor : color;
updateColorUI();
}
public void setColor(final Color color) {
this.color = color;
ButtonUI ui = getUI();
if (ui instanceof ColoredRadioButtonUI) {
((ColoredRadioButtonUI) ui).setColor(color);
}
SwingUtilities.invokeLater(this::updateUI);
updateColorUI();
}
public void setFocusColor(final Color color) {
this.focusColor = color;
updateColorUI();
}
private void updateColorUI() {
ColoredRadioButtonUI ui = DarkUIUtil.getUIOfType(getUI(), ColoredRadioButtonUI.class);
if (ui != null) ui.setColors(color, focusColor);
repaint();
}
public Color getColor() {
return color;
}
@Override
protected void setUI(final ComponentUI newUI) {
if (!(newUI instanceof ColoredRadioButtonUI)) {
throw new IllegalArgumentException("UI must be of type ColoredRadioButtonUI");
}
super.setUI(newUI);
}
@Override
public void updateUI() {
setUI(new ColoredRadioButtonUI(color));
setUI(new ColoredRadioButtonUI(color, focusColor));
}
protected static class ColoredRadioButtonUI extends DarkRadioButtonUI {
private static final String[] PROPERTIES = {
"Icons.RadioButton.activeFillColor",
private static final String[] PROPERTIES = {"Icons.RadioButton.activeFillColor",
"Icons.RadioButton.activeBorderColor",
"Icons.RadioButtonDisabled.inactiveFillColor",
"Icons.RadioButtonDisabled.inactiveBorderColor",
@ -94,45 +126,73 @@ public class ColoredRadioButton extends JRadioButton {
"Icons.RadioButtonSelectedFocused.focusSelectedBorderColor",
"Icons.RadioButtonSelectedFocused.selectionFocusSelectedColor",
"Icons.RadioButtonSelectedFocused.glowFocus",
"Icons.RadioButtonSelectedFocused.glowOpacity"
};
private static final String[] COLOR_PROPERTIES = {
"Icons.RadioButton.activeFillColor",
"Icons.RadioButtonSelectedFocused.glowOpacity"};
private static final String[] COLOR_PROPERTIES = {"Icons.RadioButton.activeFillColor",
"Icons.RadioButton.activeBorderColor",
"Icons.RadioButtonFocused.activeFillColor",
"Icons.RadioButtonFocused.focusBorderColor",
"Icons.RadioButtonSelected.selectedFillColor",
"Icons.RadioButtonSelected.selectedBorderColor",
"Icons.RadioButtonSelectedFocused.selectedFillColor",
"Icons.RadioButtonSelectedFocused.focusSelectedBorderColor"
};
"Icons.RadioButtonSelectedFocused.focusSelectedBorderColor"};
private static final String[] FOCUS_COLOR_PROPERTIES = {"Icons.RadioButtonFocused.glowFocus",
"Icons.RadioButtonSelectedFocused.glowFocus"};
private static final String[] FOREGROUND_PROPERTIES = {"Icons.RadioButtonSelected.selectionSelectedColor",
"Icons.RadioButtonSelectedFocused.selectionFocusSelectedColor"};
private static final double MIN_FG_CONTRAST = 0.6;
private Properties propertyMap;
private Icon stateIcon;
private final Color color;
private Color color;
private Color focusColor;
private Color patchedColor;
private Color patchedFocusColor;
private boolean patched;
private static final AccentColorAdjustmentTask adjustment = new AccentColorAdjustmentTask();
public ColoredRadioButtonUI(final Color color) {
public ColoredRadioButtonUI(final Color color, final Color focusColor) {
super();
this.color = color;
this.focusColor = focusColor;
}
@Override
protected void installIcons() {
super.installIcons();
setColor(color);
patchColors(color, focusColor);
}
public void setColor(final Color color) {
if (color == null) return;
public void setColors(final Color color, final Color focusColor) {
this.color = color;
this.focusColor = focusColor != null ? focusColor : color;
}
@Override
public void update(final Graphics g, final JComponent c) {
if (patchedColor != color || patchedFocusColor != focusColor) {
patchColors(color, focusColor);
}
super.update(g, c);
}
private void patchColors(final Color color, final Color focusColor) {
if (color == null || (patched && patchedColor == color && patchedFocusColor == focusColor)) {
return;
}
this.patchedColor = color;
this.patchedFocusColor = focusColor;
IconLoader loader = DarkUIUtil.ICON_LOADER;
Theme theme = LafManager.getTheme();
Properties props = new Properties();
UIDefaults defaults = UIManager.getLookAndFeelDefaults();
theme.loadDefaults(props, defaults);
Color c = color == DEFAULT_FILLED ? (Color) props.get("widgetFillDefault") : color;
adjustment.applyColors(LafManager.getTheme(), props, c, null);
PropertyLoader.putProperties(PropertyLoader.loadProperties(DarkLaf.class, "radioButton", "properties/ui/"),
Color accentCol = color == DEFAULT_FILLED ? (Color) props.get("widgetFillDefault") : color;
Color focusCol = color == DEFAULT_FILLED ? accentCol : focusColor;
adjustment.applyColors(LafManager.getTheme(), props, accentCol, null);
PropertyLoader.putProperties(PropertyLoader.loadProperties(DarkLaf.class, "radioButton",
"properties/ui/"),
props, defaults);
PropertyLoader.putProperties(PropertyLoader.loadProperties(DarkLaf.class, "radioButton",
"properties/icons/"),
@ -142,7 +202,15 @@ public class ColoredRadioButton extends JRadioButton {
propertyMap.put(prop, props.get(prop));
}
for (String prop : COLOR_PROPERTIES) {
propertyMap.put(prop, c);
propertyMap.put(prop, accentCol);
}
for (String prop : FOCUS_COLOR_PROPERTIES) {
propertyMap.put(prop, focusCol);
}
for (String prop : FOREGROUND_PROPERTIES) {
Color fg = ForegroundColorGenerationTask.makeAdjustedForeground((Color) props.get(prop),
accentCol, MIN_FG_CONTRAST);
propertyMap.put(prop, fg);
}
stateIcon = new StateIcon(new Icon[]{load(loader, "control/radio.svg"),
@ -151,6 +219,7 @@ public class ColoredRadioButton extends JRadioButton {
load(loader, "control/radioSelected.svg"),
load(loader, "control/radioSelectedDisabled.svg"),
load(loader, "control/radioSelectedFocused.svg")});
patched = true;
}
private Icon load(final IconLoader loader, final String name) {
@ -159,7 +228,7 @@ public class ColoredRadioButton extends JRadioButton {
@Override
protected Icon getStateIcon(final AbstractButton b) {
return color != null ? stateIcon : super.getStateIcon(b);
return patched ? stateIcon : super.getStateIcon(b);
}
}
}

2
core/src/main/java/com/github/weisj/darklaf/graphics/StringPainter.java

@ -163,7 +163,7 @@ public class StringPainter {
* Ensure the background color has sufficient contrast to the foreground.
*/
Color fg = g.getColor();
double brightness = ColorUtil.getBrightness(fg);
double brightness = ColorUtil.getPerceivedBrightness(fg);
bgColor = brightness > 127 ? Color.BLACK : Color.WHITE;
}

39
core/src/main/java/com/github/weisj/darklaf/settings/DefaultSettingsConfiguration.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.settings;
import com.github.weisj.darklaf.LafManager;
import com.github.weisj.darklaf.theme.Theme;
public class DefaultSettingsConfiguration extends SettingsConfiguration {
public DefaultSettingsConfiguration() {
setEnabledSystemPreferences(LafManager.isPreferenceChangeReportingEnabled());
Theme theme = LafManager.getTheme();
setTheme(theme);
setFontSizeRule(theme.getFontSizeRule());
setAccentColorRule(theme.getAccentColorRule());
}
}

255
core/src/main/java/com/github/weisj/darklaf/settings/SettingsConfiguration.java

@ -0,0 +1,255 @@
/*
* 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.settings;
import com.github.weisj.darklaf.LafManager;
import com.github.weisj.darklaf.platform.ThemePreferencesHandler;
import com.github.weisj.darklaf.theme.Theme;
import com.github.weisj.darklaf.theme.info.AccentColorRule;
import com.github.weisj.darklaf.theme.info.FontSizeRule;
public class SettingsConfiguration {
private boolean isSystemPreferencesEnabled;
private boolean isAccentColorFollowsSystem;
private boolean isFontSizeFollowsSystem;
private boolean isThemeFollowsSystem;
private boolean isSelectionColorFollowsSystem;
private AccentColorRule accentColorRule;
private FontSizeRule fontSizeRule;
private Theme theme;
public void load(final SettingsConfiguration config) {
setEnabledSystemPreferences(config.isSystemPreferencesEnabled());
setAccentColorFollowsSystem(config.isAccentColorFollowsSystem());
setSelectionColorFollowsSystem(config.isSelectionColorFollowsSystem());
setFontSizeFollowsSystem(config.isFontSizeFollowsSystem());
setThemeFollowsSystem(config.isThemeFollowsSystem());
setFontSizeRule(config.getFontSizeRule());
setAccentColorRule(config.getAccentColorRule());
setTheme(config.getTheme());
}
/**
* Returns whether the option to follow the system settings is enabled.
*
* @return true if enabled.
* @see #isSystemPreferencesEnabled() (boolean)
* @see #isThemeFollowsSystem()
* @see #isAccentColorFollowsSystem()
* @see #isSelectionColorFollowsSystem()
* @see #isFontSizeFollowsSystem()
*/
public boolean isSystemPreferencesEnabled() {
return isSystemPreferencesEnabled;
}
/**
* Returns whether the accent color follows the system settings.
*
* @return true if accent color follows system settings.
* @see #setAccentColorFollowsSystem(boolean)
*/
public boolean isAccentColorFollowsSystem() {
return isAccentColorFollowsSystem;
}
/**
* Returns whether the font size follows the system settings.
*
* @return true if font size follows system settings.
* @see #setFontSizeFollowsSystem(boolean)
*/
public boolean isFontSizeFollowsSystem() {
return isFontSizeFollowsSystem;
}
/**
* Returns whether the selection color follows the system settings.
*
* @return true if selection color follows system settings.
* @see #setSelectionColorFollowsSystem(boolean)
*/
public boolean isSelectionColorFollowsSystem() {
return isSelectionColorFollowsSystem;
}
/**
* Returns whether the theme follows the system settings.
*
* @return true if theme follows system settings.
* @see #setThemeFollowsSystem(boolean)
*/
public boolean isThemeFollowsSystem() {
return isThemeFollowsSystem;
}
/**
* Get the currently selected accent color rule. This is not the same as the rule of {@link LafManager#getTheme()}
* as the current settings might not have been applied.
*
* @return the current selected accent color rule.
* @see #setAccentColorRule(AccentColorRule)
*/
public AccentColorRule getAccentColorRule() {
return accentColorRule;
}
/**
* Get the currently selected font size rule. This is not the same as the rule of {@link LafManager#getTheme()} as
* the current settings might not have been applied.
*
* @return the current selected font size rule.
* @see #setFontSizeRule(FontSizeRule)
*/
public FontSizeRule getFontSizeRule() {
return fontSizeRule;
}
/**
* Get the currently selected theme. This is not the same as {@link LafManager#getTheme()} as the current settings
* might not have been applied.
*
* @return the current selected theme.
* @see #setTheme(Theme)
*/
public Theme getTheme() {
return theme;
}
/**
* Enables the option to follow system preferences.
*
* @param enabled true if enabled.
* @see #setAccentColorFollowsSystem(boolean)
* @see #setSelectionColorFollowsSystem(boolean)
* @see #setFontSizeFollowsSystem(boolean)
* @see #setThemeFollowsSystem(boolean)
*/
public void setEnabledSystemPreferences(final boolean enabled) {
isSystemPreferencesEnabled = enabled;
}
/**
* Sets whether the accent color should follow the system settings. This only works if {@link
* #isSelectionColorFollowsSystem()} is true.
*
* @param accentColorFollowsSystem true if accent color should follow system.
* @see #isAccentColorFollowsSystem()
*/
public void setAccentColorFollowsSystem(final boolean accentColorFollowsSystem) {
isAccentColorFollowsSystem = accentColorFollowsSystem;
}
/**
* Sets whether the font size should follow the system settings. This only works if {@link
* #isSelectionColorFollowsSystem()} is true.
*
* @param fontSizeFollowsSystem true if font size should follow system.
* @see #isFontSizeFollowsSystem()
*/
public void setFontSizeFollowsSystem(final boolean fontSizeFollowsSystem) {
isFontSizeFollowsSystem = fontSizeFollowsSystem;
}
/**
* Sets whether the selection color should follow the system settings. This only works if {@link
* #isSelectionColorFollowsSystem()} is true.
*
* @param selectionColorFollowsSystem true if selection color should follow system.
* @see #isSelectionColorFollowsSystem()
*/
public void setSelectionColorFollowsSystem(final boolean selectionColorFollowsSystem) {
isSelectionColorFollowsSystem = selectionColorFollowsSystem;
}
/**
* Sets whether the theme should follow the system settings. This only works if {@link
* #isSelectionColorFollowsSystem()} is true.
*
* @param themeFollowsSystem true if theme should follow system.
* @see #isThemeFollowsSystem()
*/
public void setThemeFollowsSystem(final boolean themeFollowsSystem) {
isThemeFollowsSystem = themeFollowsSystem;
}
/**
* Sets the font accent color rule.
*
* @param accentColorRule the accent color rule.
* @see #getAccentColorRule()
*/
public void setAccentColorRule(final AccentColorRule accentColorRule) {
this.accentColorRule = accentColorRule;
}
/**
* Sets the font size rule.
*
* @param fontSizeRule the font size rule.
* @see #getFontSizeRule()
*/
public void setFontSizeRule(final FontSizeRule fontSizeRule) {
this.fontSizeRule = fontSizeRule;
}
/**
* Sets the theme.
*
* @param theme the theme.
* @see #getTheme()
*/
public void setTheme(final Theme theme) {
this.theme = theme;
}
public boolean isSystemPreferencesSupported() {
return ThemePreferencesHandler.getSharedInstance().canReport();
}
public boolean isSystemAccentColorSupported() {
return isSystemPreferencesEnabled()
&& ThemePreferencesHandler.getSharedInstance().supportsNativeAccentColor();
}
public boolean isSystemFontSizeSupported() {
return isSystemPreferencesEnabled()
&& ThemePreferencesHandler.getSharedInstance().supportsNativeFontSize();
}
public boolean isSystemSelectionColorSupported() {
return isSystemPreferencesEnabled()
&& ThemePreferencesHandler.getSharedInstance().supportsNativeSelectionColor();
}
public boolean isSystemThemeSupported() {
return isSystemPreferencesEnabled()
&& ThemePreferencesHandler.getSharedInstance().supportsNativeTheme();
}
}

133
core/src/main/java/com/github/weisj/darklaf/settings/ThemeSettings.java

@ -38,6 +38,7 @@ import com.github.weisj.darklaf.theme.event.ThemePreferenceChangeEvent;
import com.github.weisj.darklaf.theme.event.ThemePreferenceListener;
import com.github.weisj.darklaf.theme.info.AccentColorRule;
import com.github.weisj.darklaf.theme.info.FontSizeRule;
import com.github.weisj.darklaf.theme.info.PreferredThemeStyle;
import com.github.weisj.darklaf.util.DarkUIUtil;
import com.github.weisj.darklaf.util.LazyValue;
import com.github.weisj.darklaf.util.ResourceUtil;
@ -46,11 +47,15 @@ public class ThemeSettings implements ThemePreferenceListener {
private static final LazyValue<ThemeSettings> instance = new LazyValue<>(ThemeSettings::new);
private static final LazyValue<Icon> icon = new LazyValue<>(() -> UIManager.getIcon("ThemeSettings.icon"));
private final JPanel contentPane;
private final ThemeSettingsPanel settingsPanel;
private final ResourceBundle resourceBundle = ResourceUtil.getResourceBundle("theme_settings");
private final LazyValue<ThemeSettingsPanel> settingsPanel;
private JDialog dialog;
private final SettingsConfiguration savedConfiguration;
private final SettingsConfiguration currentConfiguration;
public static ThemeSettings getInstance() {
return instance.get();
}
@ -81,19 +86,26 @@ public class ThemeSettings implements ThemePreferenceListener {
}
protected ThemeSettings() {
settingsPanel = new ThemeSettingsPanel(resourceBundle);
contentPane = new JPanel(new BorderLayout());
contentPane.add(settingsPanel, BorderLayout.CENTER);
contentPane.add(createButtonPanel(), BorderLayout.SOUTH);
settingsPanel.fetch(true);
LafManager.addThemePreferenceChangeListener(this);
currentConfiguration = new DefaultSettingsConfiguration();
savedConfiguration = new DefaultSettingsConfiguration();
settingsPanel = new LazyValue<>(() -> {
ThemeSettingsPanel panel = new ThemeSettingsPanel(resourceBundle);
panel.loadConfiguration(currentConfiguration);
return panel;
});
}
protected JDialog createDialog(final Window parent) {
JDialog dialog = new JDialog(parent);
dialog.setIconImage(IconLoader.createFrameIcon(getIcon(), dialog));
dialog.setTitle(settingsPanel.getTitle());
dialog.setTitle(getTitle());
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.add(settingsPanel.get(), BorderLayout.CENTER);
contentPane.add(createButtonPanel(), BorderLayout.SOUTH);
dialog.setContentPane(contentPane);
dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
dialog.pack();
dialog.setLocationByPlatform(true);
@ -133,7 +145,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @return the settings panel.
*/
public JComponent getSettingsPanel() {
return settingsPanel;
return settingsPanel.get();
}
/**
@ -147,7 +159,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #isFontSizeFollowsSystem()
*/
public boolean isSystemPreferencesEnabled() {
return settingsPanel.isSystemPreferencesEnabled();
return currentConfiguration.isSystemPreferencesEnabled();
}
/**
@ -157,7 +169,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #setAccentColorFollowsSystem(boolean)
*/
public boolean isAccentColorFollowsSystem() {
return settingsPanel.isAccentColorFollowsSystem();
return currentConfiguration.isAccentColorFollowsSystem();
}
/**
@ -167,7 +179,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #setFontSizeFollowsSystem(boolean)
*/
public boolean isFontSizeFollowsSystem() {
return settingsPanel.isFontSizeFollowsSystem();
return currentConfiguration.isFontSizeFollowsSystem();
}
/**
@ -177,7 +189,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #setSelectionColorFollowsSystem(boolean)
*/
public boolean isSelectionColorFollowsSystem() {
return settingsPanel.isSelectionColorFollowsSystem();
return currentConfiguration.isSelectionColorFollowsSystem();
}
/**
@ -187,7 +199,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #setThemeFollowsSystem(boolean)
*/
public boolean isThemeFollowsSystem() {
return settingsPanel.isThemeFollowsSystem();
return currentConfiguration.isThemeFollowsSystem();
}
/**
@ -198,7 +210,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #setAccentColorRule(AccentColorRule)
*/
public AccentColorRule getAccentColorRule() {
return settingsPanel.getAccentColorRule();
return currentConfiguration.getAccentColorRule();
}
/**
@ -209,7 +221,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #setFontSizeRule(FontSizeRule)
*/
public FontSizeRule getFontSizeRule() {
return settingsPanel.getFontSizeRule();
return currentConfiguration.getFontSizeRule();
}
/**
@ -220,7 +232,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #setTheme(Theme)
*/
public Theme getTheme() {
return settingsPanel.getTheme();
return currentConfiguration.getTheme();
}
/**
@ -233,7 +245,8 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #setThemeFollowsSystem(boolean)
*/
public void setEnabledSystemPreferences(final boolean enabled) {
settingsPanel.setEnabledSystemPreferences(enabled);
currentConfiguration.setEnabledSystemPreferences(enabled);
updateSettingsPanel();
}
/**
@ -244,7 +257,8 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #isAccentColorFollowsSystem()
*/
public void setAccentColorFollowsSystem(final boolean accentColorFollowsSystem) {
settingsPanel.setAccentColorFollowsSystem(accentColorFollowsSystem);
currentConfiguration.setAccentColorFollowsSystem(accentColorFollowsSystem);
updateSettingsPanel();
}
/**
@ -255,7 +269,8 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #isFontSizeFollowsSystem()
*/
public void setFontSizeFollowsSystem(final boolean fontSizeFollowsSystem) {
settingsPanel.setFontSizeFollowsSystem(fontSizeFollowsSystem);
currentConfiguration.setFontSizeFollowsSystem(fontSizeFollowsSystem);
updateSettingsPanel();
}
/**
@ -266,7 +281,8 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #isSelectionColorFollowsSystem()
*/
public void setSelectionColorFollowsSystem(final boolean selectionColorFollowsSystem) {
settingsPanel.setSelectionColorFollowsSystem(selectionColorFollowsSystem);
currentConfiguration.setSelectionColorFollowsSystem(selectionColorFollowsSystem);
updateSettingsPanel();
}
/**
@ -277,7 +293,8 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #isThemeFollowsSystem()
*/
public void setThemeFollowsSystem(final boolean themeFollowsSystem) {
settingsPanel.setThemeFollowsSystem(themeFollowsSystem);
currentConfiguration.setThemeFollowsSystem(themeFollowsSystem);
updateSettingsPanel();
}
/**
@ -287,7 +304,8 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #getAccentColorRule()
*/
public void setAccentColorRule(final AccentColorRule accentColorRule) {
settingsPanel.setAccentColorRule(accentColorRule);
currentConfiguration.setAccentColorRule(accentColorRule);
updateSettingsPanel();
}
/**
@ -297,7 +315,9 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #getFontSizeRule()
*/
public void setFontSizeRule(final FontSizeRule fontSizeRule) {
settingsPanel.setFontSizeRule(fontSizeRule);
currentConfiguration.setFontSizeRule(fontSizeRule);
updateSettingsPanel();
}
/**
@ -307,7 +327,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #getTheme()
*/
public void setTheme(final Theme theme) {
settingsPanel.setTheme(theme);
currentConfiguration.setTheme(theme);
}
protected Component createButtonPanel() {
@ -333,7 +353,7 @@ public class ThemeSettings implements ThemePreferenceListener {
box.add(ok);
box.add(cancel);
box.add(apply);
box.setBorder(settingsPanel.getBorder());
box.setBorder(settingsPanel.get().getBorder());
return box;
}
@ -341,14 +361,29 @@ public class ThemeSettings implements ThemePreferenceListener {
* Updates all values according to the current settings.
*/
public void refresh() {
settingsPanel.fetch(true);
currentConfiguration.setEnabledSystemPreferences(LafManager.isPreferenceChangeReportingEnabled());
updateSettingsPanel();
}
private void updateSettingsPanel() {
settingsPanel.ifPresent(p -> p.loadConfiguration(currentConfiguration));
}
private void fetchFromSettingsPanel() {
settingsPanel.ifPresent(ThemeSettingsPanel::updateConfiguration);
}
/**
* Saves the settings.
*/
public void save() {
settingsPanel.saveSettings();
fetchFromSettingsPanel();
LafManager.enabledPreferenceChangeReporting(currentConfiguration.isSystemPreferencesEnabled());
savedConfiguration.load(currentConfiguration);
}
public void setConfiguration(final SettingsConfiguration configuration) {
this.currentConfiguration.load(configuration);
}
/**
@ -363,7 +398,37 @@ public class ThemeSettings implements ThemePreferenceListener {
* Sets the theme according to the selected options. Does not save the settings.
*/
public void peek() {
applyTheme(settingsPanel.getEffectiveTheme());
applyTheme(getEffectiveTheme());
}
private Theme getEffectiveTheme() {
return getEffectiveTheme(LafManager.getPreferredThemeStyle());
}
private Theme getEffectiveTheme(final PreferredThemeStyle themeStyle) {
Theme baseTheme = getEffectiveBaseTheme(themeStyle);
if (baseTheme == null) return null;
FontSizeRule fontSizeRule = getEffectiveFontSizeRule(baseTheme, themeStyle);
AccentColorRule accentColorRule = getEffectiveAccentColorRule(baseTheme);
return baseTheme.derive(fontSizeRule, accentColorRule);
}
private Theme getEffectiveBaseTheme(final PreferredThemeStyle preferredThemeStyle) {
return isThemeFollowsSystem()
? LafManager.themeForPreferredStyle(preferredThemeStyle)
: getTheme();
}
private FontSizeRule getEffectiveFontSizeRule(final Theme theme, final PreferredThemeStyle preferredThemeStyle) {
if (theme == null) return FontSizeRule.getDefault();
return isFontSizeFollowsSystem()
? preferredThemeStyle.getFontSizeRule()
: getFontSizeRule();
}
private AccentColorRule getEffectiveAccentColorRule(final Theme theme) {
if (theme == null) return AccentColorRule.getDefault();
return currentConfiguration.getAccentColorRule();
}
/**
@ -372,7 +437,7 @@ public class ThemeSettings implements ThemePreferenceListener {
* @see #save()
*/
public void revert() {
settingsPanel.discardChanges();
currentConfiguration.load(savedConfiguration);
refresh();
}
@ -381,7 +446,7 @@ public class ThemeSettings implements ThemePreferenceListener {
if (LafManager.getTheme().appearsEqualTo(theme)) return;
SwingUtilities.invokeLater(() -> {
LafManager.installTheme(theme);
settingsPanel.fetch(true);
refresh();
});
}
@ -400,12 +465,12 @@ public class ThemeSettings implements ThemePreferenceListener {
* @return the title
*/
public String getTitle() {
return settingsPanel.getTitle();
return resourceBundle.getString("title");
}
@Override
public void themePreferenceChanged(final ThemePreferenceChangeEvent e) {
settingsPanel.fetch(e.getPreferredThemeStyle());
applyTheme(settingsPanel.getEffectiveTheme(e.getPreferredThemeStyle()));
refresh();
applyTheme(getEffectiveTheme(e.getPreferredThemeStyle()));
}
}

496
core/src/main/java/com/github/weisj/darklaf/settings/ThemeSettingsPanel.java

@ -25,7 +25,6 @@
package com.github.weisj.darklaf.settings;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.function.Supplier;
@ -56,7 +55,8 @@ import com.github.weisj.darklaf.util.Alignment;
public class ThemeSettingsPanel extends JPanel {
private final ResourceBundle resourceBundle;
private Icon icon;
private final SettingsPanelConfiguration settingsConfiguration;
private JCheckBox fontSizeFollowsSystem;
private JCheckBox accentColorFollowsSystem;
@ -69,11 +69,6 @@ public class ThemeSettingsPanel extends JPanel {
private ButtonGroup bgSelection;
private ButtonGroup bgAccent;
private boolean followFontSize;
private boolean followAccentColor;
private boolean followSelectionColor;
private boolean followTheme;
private boolean systemPreferences;
private Color defaultAccentColor;
private Color defaultSelectionColor;
private ColoredRadioButton customAccent;
@ -83,6 +78,7 @@ public class ThemeSettingsPanel extends JPanel {
public ThemeSettingsPanel(final ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
this.settingsConfiguration = new SettingsPanelConfiguration();
init();
}
@ -91,93 +87,38 @@ public class ThemeSettingsPanel extends JPanel {
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
add(createGeneralSettings(), BorderLayout.CENTER);
add(createMonitorSettings(), BorderLayout.SOUTH);
fetch(true);
update();
}
public void saveSettings() {
systemPreferences = !enabledSystemPreferences.getTristateModel().isDeselected();
followTheme = fontSizeFollowsSystem.isSelected();
followAccentColor = accentColorFollowsSystem.isSelected();
followSelectionColor = selectionColorFollowsSystem.isSelected();
followFontSize = fontSizeFollowsSystem.isSelected();
LafManager.enabledPreferenceChangeReporting(!enabledSystemPreferences.getTristateModel().isDeselected());
}
public void loadConfiguration(final SettingsConfiguration configuration) {
themeComboBox.setModel(LafManager.getThemeComboBoxModel());
settingsConfiguration.load(configuration);
settingsConfiguration.setAccentColorRule(settingsConfiguration.getAccentColorRule());
public void discardChanges() {
setFontSizeFollowsSystem(followFontSize);
setThemeFollowsSystem(followTheme);
setAccentColorFollowsSystem(followAccentColor);
setSelectionColorFollowsSystem(followSelectionColor);
setEnabledSystemPreferences(systemPreferences);
update();
}
private void update() {
Theme selectedTheme = (Theme) themeComboBox.getSelectedItem();
if (selectedTheme == null) selectedTheme = LafManager.getTheme();
boolean enabled = !enabledSystemPreferences.getTristateModel().isDeselected();
themeFollowsSystem.setEnabled(enabled);
accentColorFollowsSystem.setEnabled(enabled);
selectionColorFollowsSystem.setEnabled(enabled);
fontSizeFollowsSystem.setEnabled(enabled);
if (enabledSystemPreferences.isSelected()) {
themeFollowsSystem.setSelected(themeFollowsSystem.isSelected() && themeFollowsSystem.isEnabled());
accentColorFollowsSystem.setSelected(accentColorFollowsSystem.isSelected()
&& accentColorFollowsSystem.isEnabled());
selectionColorFollowsSystem.setSelected(selectionColorFollowsSystem.isSelected()
&& selectionColorFollowsSystem.isEnabled());
fontSizeFollowsSystem.setSelected(fontSizeFollowsSystem.isSelected() && fontSizeFollowsSystem.isEnabled());
}
enabledSystemPreferences.setEnabled(ThemePreferencesHandler.getSharedInstance().canReport());
themeComboBox.setEnabled(!(isThemeFollowsSystem() && isSystemPreferencesEnabled()));
setEnabledSystemPreferences(isSystemPreferencesEnabled());
enableButtonGroup(bgAccent, selectedTheme.supportsCustomAccentColor()
&& !accentColorFollowsSystem.isSelected());
enableButtonGroup(bgSelection, selectedTheme.supportsCustomSelectionColor()
&& !selectionColorFollowsSystem.isSelected());
fontSlider.setEnabled(!(isFontSizeFollowsSystem() && isSystemPreferencesEnabled()));
}
protected void fetch(final PreferredThemeStyle themeStyle, final boolean ignoreSettings) {
Theme theme = LafManager.themeForPreferredStyle(themeStyle);
fetch(theme, ignoreSettings);
}
enabledSystemPreferences.setEnabled(settingsConfiguration.isSystemPreferencesSupported());
protected void fetch(final Theme theme, final boolean ignoreSettings) {
Theme selectedTheme = (Theme) themeComboBox.getSelectedItem();
Theme currentTheme = LafManager.getTheme();
themeComboBox.setModel(LafManager.getThemeComboBoxModel());
if (ignoreSettings || isThemeFollowsSystem()) {
setTheme(isThemeFollowsSystem() ? theme : currentTheme);
} else {
themeComboBox.setSelectedItem(selectedTheme);
}
if (ignoreSettings || isFontSizeFollowsSystem()) {
setFontSizeRule(isFontSizeFollowsSystem()
? theme.getFontSizeRule()
: currentTheme.getFontSizeRule());
}
if (ignoreSettings || isAccentColorFollowsSystem()) {
setAccentColor(getAccentColor(isAccentColorFollowsSystem() ? theme : currentTheme, true));
}
if (ignoreSettings || isSelectionColorFollowsSystem()) {
setSelectionColor(getSelectionColor(isSelectionColorFollowsSystem() ? theme : currentTheme, true));
}
if (!ignoreSettings) {
setEnabledSystemPreferences(LafManager.isPreferenceChangeReportingEnabled());
}
update();
}
themeFollowsSystem.setEnabled(enabled && settingsConfiguration.isSystemThemeSupported());
accentColorFollowsSystem.setEnabled(enabled && settingsConfiguration.isSystemAccentColorSupported());
selectionColorFollowsSystem.setEnabled(enabled && settingsConfiguration.isSystemSelectionColorSupported());
fontSizeFollowsSystem.setEnabled(enabled && settingsConfiguration.isSystemFontSizeSupported());
public void fetch(final PreferredThemeStyle themeStyle) {
fetch(themeStyle, false);
settingsConfiguration.setEnabledSystemPreferences(settingsConfiguration.isSystemPreferencesEnabled());
enableButtonGroup(bgAccent, !settingsConfiguration.isAccentColorFollowsSystem()
&& settingsConfiguration.getSelectedTheme().supportsCustomAccentColor());
enableButtonGroup(bgSelection, !settingsConfiguration.isSelectionColorFollowsSystem()
&& settingsConfiguration.getSelectedTheme().supportsCustomSelectionColor());
themeComboBox.setEnabled(!settingsConfiguration.isThemeFollowsSystem());
fontSlider.setEnabled(!settingsConfiguration.isFontSizeFollowsSystem());
}
public void fetch(final boolean ignoreSettings) {
fetch(LafManager.getPreferredThemeStyle(), ignoreSettings);
public void updateConfiguration() {
ThemeSettings.getInstance().setConfiguration(settingsConfiguration);
}
private boolean updateButtonGroup(final ButtonGroup bg, final Color currentColor,
@ -194,18 +135,6 @@ public class ThemeSettingsPanel extends JPanel {
return false;
}
public Theme getEffectiveTheme(final PreferredThemeStyle preferredThemeStyle) {
Theme theme = getTheme(preferredThemeStyle);
if (theme == null) return null;
FontSizeRule fontSizeRule = getFontSizeRule(theme, preferredThemeStyle);
AccentColorRule accentColorRule = getAccentColorRule(theme);
return theme.derive(fontSizeRule, accentColorRule);
}
public Theme getEffectiveTheme() {
return getEffectiveTheme(LafManager.getPreferredThemeStyle());
}
protected Color getSelectedColor(final ButtonGroup bg, final AbstractButton defaultButton) {
Enumeration<AbstractButton> enumeration = bg.getElements();
while (enumeration.hasMoreElements()) {
@ -244,21 +173,29 @@ public class ThemeSettingsPanel extends JPanel {
defaultSelectionColor = createDefaultColor("themeSelectionColor");
defaultSelection = addColoredButton(bgSelection, selectionBox, defaultSelectionColor,
resourceBundle.getString("color_default"));
AbstractButton selectionBlue = addColoredButton(bgSelection, selectionBox, MacOSColors.SELECTION_BLUE,
AbstractButton selectionBlue = addColoredButton(bgSelection, selectionBox,
MacOSColors.SELECTION_BLUE, MacOSColors.ACCENT_BLUE,
resourceBundle.getString("color_blue"));
AbstractButton selectionPurple = addColoredButton(bgSelection, selectionBox, MacOSColors.SELECTION_PURPLE,
AbstractButton selectionPurple = addColoredButton(bgSelection, selectionBox,
MacOSColors.SELECTION_PURPLE, MacOSColors.ACCENT_LILAC,
resourceBundle.getString("color_purple"));
AbstractButton selectionPink = addColoredButton(bgSelection, selectionBox, MacOSColors.SELECTION_PINK,
AbstractButton selectionPink = addColoredButton(bgSelection, selectionBox,
MacOSColors.SELECTION_PINK, MacOSColors.ACCENT_ROSE,
resourceBundle.getString("color_pink"));
AbstractButton selectionRed = addColoredButton(bgSelection, selectionBox, MacOSColors.SELECTION_RED,
AbstractButton selectionRed = addColoredButton(bgSelection, selectionBox,
MacOSColors.SELECTION_RED, MacOSColors.ACCENT_RED,
resourceBundle.getString("color_red"));
AbstractButton selectionOrange = addColoredButton(bgSelection, selectionBox, MacOSColors.SELECTION_ORANGE,
AbstractButton selectionOrange = addColoredButton(bgSelection, selectionBox,
MacOSColors.SELECTION_ORANGE, MacOSColors.ACCENT_ORANGE,
resourceBundle.getString("color_orange"));
AbstractButton selectionYellow = addColoredButton(bgSelection, selectionBox, MacOSColors.SELECTION_YELLOW,
AbstractButton selectionYellow = addColoredButton(bgSelection, selectionBox,
MacOSColors.SELECTION_YELLOW, MacOSColors.ACCENT_YELLOW,
resourceBundle.getString("color_yellow"));
AbstractButton selectionGreen = addColoredButton(bgSelection, selectionBox, MacOSColors.SELECTION_GREEN,
AbstractButton selectionGreen = addColoredButton(bgSelection, selectionBox,
MacOSColors.SELECTION_GREEN, MacOSColors.ACCENT_GREEN,
resourceBundle.getString("color_green"));
AbstractButton selectionGraphite = addColoredButton(bgSelection, selectionBox, MacOSColors.SELECTION_GRAPHITE,
AbstractButton selectionGraphite = addColoredButton(bgSelection, selectionBox,
MacOSColors.SELECTION_GRAPHITE, MacOSColors.ACCENT_GRAPHITE,
resourceBundle.getString("color_gray"));
customSelection = addCustomButton(bgSelection, selectionBox, currentSelectionColor, defaultSelectionColor,
resourceBundle.getString("color_custom"));
@ -324,116 +261,6 @@ public class ThemeSettingsPanel extends JPanel {
return new ThemedColor(key);
}
public boolean isSystemPreferencesEnabled() {
return !enabledSystemPreferences.getTristateModel().isDeselected() && enabledSystemPreferences.isEnabled();
}
public boolean isAccentColorFollowsSystem() {
return accentColorFollowsSystem.isSelected() && accentColorFollowsSystem.isEnabled();
}
public boolean isFontSizeFollowsSystem() {
return fontSizeFollowsSystem.isSelected() && fontSizeFollowsSystem.isEnabled();
}
public boolean isSelectionColorFollowsSystem() {
return selectionColorFollowsSystem.isSelected() && selectionColorFollowsSystem.isEnabled();
}
public boolean isThemeFollowsSystem() {
return themeFollowsSystem.isSelected() && themeFollowsSystem.isEnabled();
}
public Theme getTheme() {
return getTheme(LafManager.getPreferredThemeStyle());
}
protected Theme getTheme(final PreferredThemeStyle preferredThemeStyle) {
return isThemeFollowsSystem()
? LafManager.themeForPreferredStyle(preferredThemeStyle)
: (Theme) themeComboBox.getSelectedItem();
}
public FontSizeRule getFontSizeRule() {
PreferredThemeStyle preferredThemeStyle = LafManager.getPreferredThemeStyle();
return getFontSizeRule(getTheme(preferredThemeStyle), preferredThemeStyle);
}
protected FontSizeRule getFontSizeRule(final Theme theme, final PreferredThemeStyle preferredThemeStyle) {
if (theme == null) return FontSizeRule.getDefault();
return isFontSizeFollowsSystem()
? preferredThemeStyle.getFontSizeRule()
: FontSizeRule.relativeAdjustment(fontSlider.getValue());
}
public AccentColorRule getAccentColorRule() {
PreferredThemeStyle preferredThemeStyle = LafManager.getPreferredThemeStyle();
return getAccentColorRule(getTheme(preferredThemeStyle));
}
protected AccentColorRule getAccentColorRule(final Theme theme) {
if (theme == null) return AccentColorRule.getDefault();
Color accentColor = getAccentColor(theme, isAccentColorFollowsSystem());
Color selectionColor = getSelectionColor(theme, isSelectionColorFollowsSystem());
return AccentColorRule.fromColor(accentColor, selectionColor);
}
protected Color getAccentColor(final Theme theme, final boolean useThemeColor) {
return theme.supportsCustomAccentColor() ? useThemeColor ? theme.getAccentColorRule().getAccentColor()
: getSelectedColor(bgAccent, defaultAccent)
: null;
}
protected Color getSelectionColor(final Theme theme, final boolean useThemeColor) {
return theme.supportsCustomSelectionColor() ? useThemeColor ? theme.getAccentColorRule().getSelectionColor()
: getSelectedColor(bgSelection, defaultSelection)
: null;
}
public void setEnabledSystemPreferences(final boolean enabled) {
TristateState state = TristateState.DESELECTED;
if (enabled
&& (isFontSizeFollowsSystem() || !fontSizeFollowsSystem.isEnabled())
&& (isThemeFollowsSystem() || !themeFollowsSystem.isEnabled())
&& (isAccentColorFollowsSystem() || !accentColorFollowsSystem.isEnabled())
&& (isSelectionColorFollowsSystem() || !selectionColorFollowsSystem.isEnabled())) {
state = TristateState.SELECTED;
} else if (enabled) {
enabledSystemPreferences.getTristateModel().setIndeterminate();
return;
}
enabledSystemPreferences.getTristateModel().setState(state);
}
public void setAccentColorFollowsSystem(final boolean accentColorFollowsSystem) {
this.accentColorFollowsSystem.setSelected(accentColorFollowsSystem);
}
public void setFontSizeFollowsSystem(final boolean fontSizeFollowsSystem) {
this.fontSizeFollowsSystem.setSelected(fontSizeFollowsSystem);
}
public void setSelectionColorFollowsSystem(final boolean selectionColorFollowsSystem) {
this.selectionColorFollowsSystem.setSelected(selectionColorFollowsSystem);
}
public void setThemeFollowsSystem(final boolean themeFollowsSystem) {
this.themeFollowsSystem.setSelected(themeFollowsSystem);
}
public void setTheme(final Theme theme) {
themeComboBox.setSelectedItem(LafManager.getClosestMatchForTheme(theme));
}
public void setAccentColorRule(final AccentColorRule accentColorRule) {
setAccentColorRule(accentColorRule.getAccentColor(), accentColorRule.getSelectionColor());
}
protected void setAccentColorRule(final Color accentColor, final Color selectionColor) {
setAccentColor(accentColor);
setSelectionColor(selectionColor);
}
protected void setAccentColor(final Color accentColor) {
setXColor(accentColor, bgAccent, customAccent, defaultAccent, defaultAccentColor);
}
@ -456,14 +283,6 @@ public class ThemeSettingsPanel extends JPanel {
}
}
public void setFontSizeRule(final FontSizeRule fontSizeRule) {
if (fontSizeRule == null) {
fontSlider.setValue(FontSizePreset.NORMAL.getPercentage());
} else {
fontSlider.setValue(fontSizeRule.getPercentage());
}
}
private JSlider createFontSlider() {
JSlider fontSlider = new JSlider() {
@Override
@ -572,10 +391,10 @@ public class ThemeSettingsPanel extends JPanel {
enabledSystemPreferences = new TristateCheckBox(resourceBundle.getString("check_system_preferences"));
ActionListener actionListener = e -> SwingUtilities.invokeLater(this::update);
enabledSystemPreferences.addChangeListener(e -> {
if (!enabledSystemPreferences.getTristateModel().isIndeterminate()) {
boolean selected = enabledSystemPreferences.getTristateModel().isSelected();
if (themeFollowsSystem.isEnabled()) themeFollowsSystem.setSelected(selected);
if (accentColorFollowsSystem.isEnabled()) accentColorFollowsSystem.setSelected(selected);
if (selectionColorFollowsSystem.isEnabled()) selectionColorFollowsSystem.setSelected(selected);
@ -583,10 +402,11 @@ public class ThemeSettingsPanel extends JPanel {
}
update();
});
themeFollowsSystem.addActionListener(actionListener);
accentColorFollowsSystem.addActionListener(actionListener);
selectionColorFollowsSystem.addActionListener(actionListener);
fontSizeFollowsSystem.addActionListener(actionListener);
themeFollowsSystem.addActionListener(e -> update());
accentColorFollowsSystem.addActionListener(e -> update());
selectionColorFollowsSystem.addActionListener(e -> update());
fontSizeFollowsSystem.addActionListener(e -> update());
enabledSystemPreferences.setSelected(LafManager.isPreferenceChangeReportingEnabled());
@ -656,34 +476,49 @@ public class ThemeSettingsPanel extends JPanel {
}
}
public ColoredRadioButton addColoredButton(final ColoredRadioButton button,
final ButtonGroup bg, final JComponent parent,
final String tipText) {
setupButton(button, bg, tipText);
parent.add(button);
return button;
private ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Color color, final String tipText) {
return addColoredButton(bg, parent, color, color, tipText);
}
public ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Color color, final AbstractButton peer,
final String tipText) {
ColoredRadioButton button = addColoredButton(new ColoredRadioButton(null, color), bg, parent, tipText);
button.addActionListener(e -> {
if (button.isSelected()) {
peer.setSelected(true);
}
});
private ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Color color, final AbstractButton peer,
final String tipText) {
return addColoredButton(bg, parent, color, color, peer, tipText);
}
private ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Color color, final Color focusColor,
final String tipText) {
return addColoredButton(bg, parent, color, focusColor, null, tipText);
}
private ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Color color, final Color focusColor,
final AbstractButton peer,
final String tipText) {
ColoredRadioButton button = addColoredButtonImpl(new ColoredRadioButton(null, color, focusColor),
bg, parent, tipText);
if (peer != null) {
button.addActionListener(e -> {
if (button.isSelected()) {
peer.setSelected(true);
}
});
}
return button;
}
public ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Color color, final String tipText) {
return addColoredButton(new ColoredRadioButton(null, color), bg, parent, tipText);
private ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Supplier<Color> colorSupplier, final String tipText) {
return addColoredButton(bg, parent, colorSupplier, colorSupplier, tipText);
}
public ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Supplier<Color> colorSupplier, final String tipText) {
return addColoredButton(new ColoredRadioButton(null, null) {
private ColoredRadioButton addColoredButton(final ButtonGroup bg, final JComponent parent,
final Supplier<Color> colorSupplier,
final Supplier<Color> focusColorSupplier,
final String tipText) {
return addColoredButtonImpl(new ColoredRadioButton(null, null) {
{
addActionListener(e -> getColor());
}
@ -692,13 +527,21 @@ public class ThemeSettingsPanel extends JPanel {
public Color getColor() {
Color c = super.getColor();
if (c == null) {
setColor(colorSupplier.get());
setColors(colorSupplier.get(), focusColorSupplier.get());
}
return super.getColor();
}
}, bg, parent, tipText);
}
private ColoredRadioButton addColoredButtonImpl(final ColoredRadioButton button,
final ButtonGroup bg, final JComponent parent,
final String tipText) {
setupButton(button, bg, tipText);
parent.add(button);
return button;
}
private void setupButton(final ColoredRadioButton button, final ButtonGroup bg, final String tipText) {
bg.add(button);
button.setName(tipText);
@ -709,7 +552,162 @@ public class ThemeSettingsPanel extends JPanel {
button.putClientProperty(ToolTipConstants.KEY_CONTEXT, context);
}
public String getTitle() {
return resourceBundle.getString("title");
private class SettingsPanelConfiguration extends SettingsConfiguration {
@Override
public boolean isSystemPreferencesEnabled() {
return !enabledSystemPreferences.getTristateModel().isDeselected() && isSystemPreferencesSupported();
}
@Override
public boolean isAccentColorFollowsSystem() {
return accentColorFollowsSystem.isSelected() && isSystemAccentColorSupported();
}
@Override
public boolean isFontSizeFollowsSystem() {
return fontSizeFollowsSystem.isSelected() && isSystemFontSizeSupported();
}
@Override
public boolean isSelectionColorFollowsSystem() {
return selectionColorFollowsSystem.isSelected() && isSystemSelectionColorSupported();
}
@Override
public boolean isThemeFollowsSystem() {
return themeFollowsSystem.isSelected() && isSystemThemeSupported();
}
@Override
public boolean isSystemAccentColorSupported() {
return super.isSystemAccentColorSupported() && getSelectedTheme().supportsCustomAccentColor();
}
@Override
public boolean isSystemSelectionColorSupported() {
return super.isSystemSelectionColorSupported() && getSelectedTheme().supportsCustomSelectionColor();
}
@Override
public AccentColorRule getAccentColorRule() {
PreferredThemeStyle preferredThemeStyle = LafManager.getPreferredThemeStyle();
return getAccentColorRule(getTheme(preferredThemeStyle));
}
private AccentColorRule getAccentColorRule(final Theme theme) {
if (theme == null) return AccentColorRule.getDefault();
Color accentColor = getAccentColor(theme, isAccentColorFollowsSystem());
Color selectionColor = getSelectionColor(theme, isSelectionColorFollowsSystem());
return AccentColorRule.fromColor(accentColor, selectionColor);
}
private Color getAccentColor(final Theme theme, final boolean useThemeColor) {
return theme.supportsCustomAccentColor()
? useThemeColor
? theme.getAccentColorRule().getAccentColor()
: getSelectedColor(bgAccent, defaultAccent)
: null;
}
private Color getSelectionColor(final Theme theme, final boolean useThemeColor) {
return theme.supportsCustomSelectionColor()
? useThemeColor
? theme.getAccentColorRule().getSelectionColor()
: getSelectedColor(bgSelection, defaultSelection)
: null;
}
@Override
public FontSizeRule getFontSizeRule() {
PreferredThemeStyle preferredThemeStyle = LafManager.getPreferredThemeStyle();
return getFontSizeRule(getTheme(preferredThemeStyle), preferredThemeStyle);
}
private FontSizeRule getFontSizeRule(final Theme theme, final PreferredThemeStyle preferredThemeStyle) {
if (theme == null) return FontSizeRule.getDefault();
return isFontSizeFollowsSystem()
? preferredThemeStyle.getFontSizeRule()
: FontSizeRule.relativeAdjustment(fontSlider.getValue()); // Todo
}
@Override
public Theme getTheme() {
return getTheme(LafManager.getPreferredThemeStyle());
}
private Theme getTheme(final PreferredThemeStyle preferredThemeStyle) {
return isThemeFollowsSystem()
? LafManager.themeForPreferredStyle(preferredThemeStyle)
: getSelectedTheme();
}
private Theme getSelectedTheme() {
return (Theme) themeComboBox.getSelectedItem();
}
@Override
public void setEnabledSystemPreferences(final boolean enabled) {
TristateState state = TristateState.DESELECTED;
if (enabled
&& (isFontSizeFollowsSystem() || !fontSizeFollowsSystem.isEnabled())
&& (isThemeFollowsSystem() || !themeFollowsSystem.isEnabled())
&& (isAccentColorFollowsSystem() || !accentColorFollowsSystem.isEnabled())
&& (isSelectionColorFollowsSystem() || !selectionColorFollowsSystem.isEnabled())) {
state = TristateState.SELECTED;
} else if (enabled) {
enabledSystemPreferences.getTristateModel().setIndeterminate();
return;
}
enabledSystemPreferences.getTristateModel().setState(state);
}
@Override
public void setAccentColorFollowsSystem(final boolean accentColorFollowsSystem) {
ThemeSettingsPanel.this.accentColorFollowsSystem.setSelected(accentColorFollowsSystem);
}
@Override
public void setFontSizeFollowsSystem(final boolean fontSizeFollowsSystem) {
ThemeSettingsPanel.this.fontSizeFollowsSystem.setSelected(fontSizeFollowsSystem);
}
@Override
public void setSelectionColorFollowsSystem(final boolean selectionColorFollowsSystem) {
ThemeSettingsPanel.this.selectionColorFollowsSystem.setSelected(selectionColorFollowsSystem);
}
@Override
public void setThemeFollowsSystem(final boolean themeFollowsSystem) {
ThemeSettingsPanel.this.themeFollowsSystem.setSelected(themeFollowsSystem);
}
@Override
public void setAccentColorRule(final AccentColorRule accentColorRule) {
if (accentColorRule == null) {
setAccentColorRule(null, null);
} else {
setAccentColorRule(accentColorRule.getAccentColor(), accentColorRule.getSelectionColor());
}
}
protected void setAccentColorRule(final Color accentColor, final Color selectionColor) {
setAccentColor(accentColor);
setSelectionColor(selectionColor);
}
@Override
public void setFontSizeRule(final FontSizeRule fontSizeRule) {
if (fontSizeRule == null) {
fontSlider.setValue(FontSizePreset.NORMAL.getPercentage());
} else {
fontSlider.setValue(fontSizeRule.getPercentage());
}
}
@Override
public void setTheme(final Theme theme) {
themeComboBox.setSelectedItem(LafManager.getClosestMatchForTheme(theme));
}
}
}

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

@ -28,9 +28,13 @@ import java.awt.*;
import java.util.List;
import java.util.Properties;
import javax.swing.plaf.ColorUIResource;
import com.github.weisj.darklaf.color.DarkColorModelHSB;
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.ColorUtil;
import com.github.weisj.darklaf.util.Pair;
public class ForegroundColorGenerationTask extends ColorAdjustmentTask {
@ -62,18 +66,56 @@ public class ForegroundColorGenerationTask extends ColorAdjustmentTask {
.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())));
.forEach(p -> properties.put(p.getSecond(), makeForeground((Color) p.getFirst(),
MIN_FOREGROUND_DIFFERENCE)));
}
public static ColorUIResource makeForeground(final Color c, final double minimumBrightnessDifference) {
double[] hsbBG = DarkColorModelHSB.RGBtoHSBValues(c.getRed(), c.getGreen(), c.getBlue());
double[] hsbFG = new double[]{hsbBG[0], 0, 1 - hsbBG[2]};
return makeAdjustedForeground(hsbFG, hsbBG, Bias.BACKGROUND, minimumBrightnessDifference);
}
public static ColorUIResource makeAdjustedForeground(final Color fg, final Color bg,
final double minimumBrightnessDifference) {
return makeAdjustedForeground(fg, bg, Bias.BACKGROUND, minimumBrightnessDifference);
}
public static ColorUIResource makeAdjustedForeground(final Color fg, final Color bg, final Bias bias,
final double minimumBrightnessDifference) {
double[] hsbBG = DarkColorModelHSB.RGBtoHSBValues(bg.getRed(), bg.getGreen(), bg.getBlue());
double[] hsbFG = DarkColorModelHSB.RGBtoHSBValues(fg.getRed(), fg.getGreen(), fg.getBlue());
return makeAdjustedForeground(hsbFG, hsbBG, bias, minimumBrightnessDifference);
}
private Color makeForeground(final Color c) {
double[] hsb = DarkColorModelHSB.RGBtoHSBValues(c.getRed(), c.getGreen(), c.getBlue());
double b = hsb[2];
double brightness = 1 - b;
double difference = Math.abs(brightness - b);
if (difference < MIN_FOREGROUND_DIFFERENCE) {
int bias = b < 0.5 ? 1 : -1;
brightness += bias * (Math.abs(MIN_FOREGROUND_DIFFERENCE - difference));
private static ColorUIResource makeAdjustedForeground(final double[] hsbFG, final double[] hsbBG, final Bias bias,
final double minimumBrightnessDifference) {
double bgBrightness = hsbBG[2];
double fgBrightness = hsbFG[2];
Bias b = bias != null ? bias : Bias.BACKGROUND;
if (b == Bias.BACKGROUND) {
Color c = DarkColorModelHSB.getColorFromHSBValues(hsbBG[0], hsbBG[1], hsbBG[2]);
double bgBright = (1 - hsbBG[1]) * ColorUtil.getPerceivedBrightness(c);
b = bgBright <= 127.5f ? Bias.WHITE : Bias.BLACK;
}
double difference = Math.abs(fgBrightness - bgBrightness);
if (difference < minimumBrightnessDifference) {
fgBrightness += b.direction * (Math.abs(minimumBrightnessDifference - difference));
}
return new DarkColorUIResource(DarkColorModelHSB.getColorFromHSBValues(hsbFG[0], hsbFG[1], fgBrightness));
}
public enum Bias {
BACKGROUND(0),
WHITE(1),
BLACK(-1);
private final int direction;
Bias(final int direction) {
this.direction = direction;
}
return DarkColorModelHSB.getColorFromHSBValues(hsb[0], 0, brightness);
}
}

2
core/src/main/java/javax/swing/text/DefaultHighlighterDark/DarkHighlightPainter.java

@ -86,7 +86,7 @@ public class DarkHighlightPainter extends DefaultHighlighter.DefaultHighlightPai
public DarkHighlightPainter(final Paint paint, final boolean rounded, final float alpha) {
super(null);
wrapper = new HighlighterColor(color);
wrapper = new HighlighterColor(null);
arcSize = UIManager.getInt("Highlight.arc");
setPaint(paint);
setRoundedEdges(rounded);

3
core/src/test/java/ui/SettingsDemo.java

@ -57,12 +57,13 @@ public class SettingsDemo implements ComponentDemo {
}
});
content.add(box, BorderLayout.SOUTH);
return content;
}
@Override
public Icon getFrameIcon() {
return ThemeSettings.getInstance().getIcon();
return ThemeSettings.getIcon();
}
@Override

14
utils/src/main/java/com/github/weisj/darklaf/util/ColorUtil.java

@ -95,9 +95,15 @@ public final class ColorUtil {
return toAlpha(color, 255);
}
public static double getBrightness(final Color c) {
return Math.sqrt(0.241 * c.getRed() * c.getRed()
+ 0.691 * c.getGreen() * c.getGreen()
+ 0.068 * c.getBlue() * c.getBlue());
/**
* Calculate the perceived brightness of a color.
*
* @param c the color.
* @return the brightness from 0 to 255.
*/
public static double getPerceivedBrightness(final Color c) {
return Math.sqrt(0.299 * c.getRed() * c.getRed()
+ 0.587 * c.getGreen() * c.getGreen()
+ 0.114 * c.getBlue() * c.getBlue());
}
}

14
utils/src/main/java/com/github/weisj/darklaf/util/LazyValue.java

@ -24,6 +24,8 @@
*/
package com.github.weisj.darklaf.util;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class LazyValue<T> {
@ -52,6 +54,18 @@ public class LazyValue<T> {
return value;
}
public void ifPresent(final Consumer<T> action) {
if (isInitialized() && value != null) {
action.accept(value);
}
}
public void ifPresentNullable(final Consumer<Optional<T>> action) {
if (isInitialized()) {
action.accept(Optional.ofNullable(value));
}
}
public T get() {
if (value == null) value = load();
return value;

Loading…
Cancel
Save