IntelliJ Themes: support customizing through properties files (issue #824)

re-written how .theme.json values are applied:
- old: .theme.json values were applied as last step to a UIDefaults object (after processing all FlatLaf properties files)
- new: .theme.json values are applied to the properties map while loading all FlatLaf properties files
This commit is contained in:
Karl Tauber
2025-03-06 13:14:04 +01:00
parent 143f96360b
commit 9b1ae5c74a
11 changed files with 870 additions and 554 deletions

View File

@@ -24,7 +24,9 @@ FlatLaf Change Log
- Extras: `FlatSVGIcon` color filters now can access painting component to - Extras: `FlatSVGIcon` color filters now can access painting component to
implement component state based color mappings. (issue #906) implement component state based color mappings. (issue #906)
- Linux: Added `libflatlaf-linux-arm64.so` for Linux on ARM64. (issue #899) - Linux: Added `libflatlaf-linux-arm64.so` for Linux on ARM64. (issue #899)
- IntelliJ Themes: Updated to latest versions. - IntelliJ Themes:
- Updated to latest versions and fixed various issues.
- Support customizing through properties files. (issue #824)
#### Fixed bugs #### Fixed bugs

View File

@@ -521,10 +521,10 @@ public abstract class FlatLaf
// load defaults from properties // load defaults from properties
List<Class<?>> lafClassesForDefaultsLoading = getLafClassesForDefaultsLoading(); List<Class<?>> lafClassesForDefaultsLoading = getLafClassesForDefaultsLoading();
if( lafClassesForDefaultsLoading != null ) if( lafClassesForDefaultsLoading == null )
UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, addons, getAdditionalDefaults(), isDark(), defaults ); lafClassesForDefaultsLoading = UIDefaultsLoader.getLafClassesForDefaultsLoading( getClass() );
else UIDefaultsLoader.loadDefaultsFromProperties( lafClassesForDefaultsLoading, addons,
UIDefaultsLoader.loadDefaultsFromProperties( getClass(), addons, getAdditionalDefaults(), isDark(), defaults ); this::applyAdditionalProperties, getAdditionalDefaults(), isDark(), defaults );
// setup default font after loading defaults from properties // setup default font after loading defaults from properties
// to allow defining "defaultFont" in properties // to allow defining "defaultFont" in properties
@@ -541,9 +541,6 @@ public abstract class FlatLaf
// initialize text antialiasing // initialize text antialiasing
putAATextInfo( defaults ); putAATextInfo( defaults );
// apply additional defaults (e.g. from IntelliJ themes)
applyAdditionalDefaults( defaults );
// allow addons modifying UI defaults // allow addons modifying UI defaults
for( FlatDefaultsAddon addon : addons ) for( FlatDefaultsAddon addon : addons )
addon.afterDefaultsLoading( this, defaults ); addon.afterDefaultsLoading( this, defaults );
@@ -564,7 +561,8 @@ public abstract class FlatLaf
return defaults; return defaults;
} }
void applyAdditionalDefaults( UIDefaults defaults ) { // apply additional properties (e.g. from IntelliJ themes)
void applyAdditionalProperties( Properties properties ) {
} }
protected List<Class<?>> getLafClassesForDefaultsLoading() { protected List<Class<?>> getLafClassesForDefaultsLoading() {

View File

@@ -16,7 +16,6 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import java.awt.Color;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@@ -25,20 +24,16 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.Map.Entry;
import javax.swing.UIDefaults;
import javax.swing.plaf.ColorUIResource;
import com.formdev.flatlaf.json.Json; import com.formdev.flatlaf.json.Json;
import com.formdev.flatlaf.json.ParseException; import com.formdev.flatlaf.json.ParseException;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.LoggingFacade;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
@@ -63,13 +58,11 @@ public class IntelliJTheme
public final boolean dark; public final boolean dark;
public final String author; public final String author;
private final boolean isMaterialUILite; private Map<String, String> jsonColors;
private Map<String, Object> jsonUI;
private Map<String, Object> jsonIcons;
private Map<String, String> colors; private Map<String, String> namedColors = Collections.emptyMap();
private Map<String, Object> ui;
private Map<String, Object> icons;
private Map<String, ColorUIResource> namedColors = Collections.emptyMap();
/** /**
* Loads a IntelliJ .theme.json file from the given input stream, * Loads a IntelliJ .theme.json file from the given input stream,
@@ -84,7 +77,7 @@ public class IntelliJTheme
try { try {
return FlatLaf.setup( createLaf( in ) ); return FlatLaf.setup( createLaf( in ) );
} catch( Exception ex ) { } catch( Exception ex ) {
LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex ); LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to load IntelliJ theme", ex );
return false; return false;
} }
} }
@@ -138,94 +131,90 @@ public class IntelliJTheme
dark = Boolean.parseBoolean( (String) json.get( "dark" ) ); dark = Boolean.parseBoolean( (String) json.get( "dark" ) );
author = (String) json.get( "author" ); author = (String) json.get( "author" );
isMaterialUILite = author.equals( "Mallowigi" ); jsonColors = (Map<String, String>) json.get( "colors" );
jsonUI = (Map<String, Object>) json.get( "ui" );
colors = (Map<String, String>) json.get( "colors" ); jsonIcons = (Map<String, Object>) json.get( "icons" );
ui = (Map<String, Object>) json.get( "ui" );
icons = (Map<String, Object>) json.get( "icons" );
} }
private void applyProperties( UIDefaults defaults ) { private void applyProperties( Properties properties ) {
if( ui == null ) if( jsonUI == null )
return; return;
defaults.put( "Component.isIntelliJTheme", true ); put( properties, "Component.isIntelliJTheme", "true" );
// enable button shadows // enable button shadows
defaults.put( "Button.paintShadow", true ); put( properties, "Button.paintShadow", "true" );
defaults.put( "Button.shadowWidth", dark ? 2 : 1 ); put( properties, "Button.shadowWidth", dark ? "2" : "1" );
Map<Object, Object> themeSpecificDefaults = removeThemeSpecificDefaults( defaults ); Map<String, String> themeSpecificProps = removeThemeSpecificProps( properties );
Set<String> jsonUIKeys = new HashSet<>();
loadNamedColors( defaults ); // Json node "colors"
loadNamedColors( properties, jsonUIKeys );
// convert Json "ui" structure to UI defaults // convert Json "ui" structure to UI properties
ArrayList<Object> defaultsKeysCache = new ArrayList<>(); for( Map.Entry<String, Object> e : jsonUI.entrySet() )
Set<String> uiKeys = new HashSet<>(); apply( e.getKey(), e.getValue(), properties, jsonUIKeys );
for( Map.Entry<String, Object> e : ui.entrySet() )
apply( e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys );
applyColorPalette( defaults ); // set FlatLaf variables
applyCheckBoxColors( defaults ); copyIfSetInJson( properties, jsonUIKeys, "@background", "Panel.background", "*.background" );
copyIfSetInJson( properties, jsonUIKeys, "@foreground", "CheckBox.foreground", "*.foreground" );
copyIfSetInJson( properties, jsonUIKeys, "@accentBaseColor",
"ColorPalette.accent", // Material UI Lite, Hiberbee
"ColorPalette.accentColor", // Dracula, One Dark
"ProgressBar.foreground",
"*.selectionBackground" );
copyIfSetInJson( properties, jsonUIKeys, "@accentUnderlineColor", "*.underlineColor", "TabbedPane.underlineColor" );
copyIfSetInJson( properties, jsonUIKeys, "@selectionBackground", "*.selectionBackground" );
copyIfSetInJson( properties, jsonUIKeys, "@selectionForeground", "*.selectionForeground" );
copyIfSetInJson( properties, jsonUIKeys, "@selectionInactiveBackground", "*.selectionInactiveBackground" );
copyIfSetInJson( properties, jsonUIKeys, "@selectionInactiveForeground", "*.selectionInactiveForeground" );
// Json node "icons/ColorPalette"
applyIconsColorPalette( properties );
// apply "CheckBox.icon." colors
applyCheckBoxColors( properties );
// copy values // copy values
for( Map.Entry<String, String> e : uiKeyCopying.entrySet() ) { for( Map.Entry<String, String> e : uiKeyCopying.entrySet() ) {
Object value = defaults.get( e.getValue() ); Object value = properties.get( e.getValue() );
if( value != null ) if( value != null )
defaults.put( e.getKey(), value ); put( properties, e.getKey(), value );
} }
// IDEA does not paint button background if disabled, but FlatLaf does // IDEA does not paint button background if disabled, but FlatLaf does
Object panelBackground = defaults.get( "Panel.background" ); put( properties, "Button.disabledBackground", "@disabledBackground" );
defaults.put( "Button.disabledBackground", panelBackground ); put( properties, "ToggleButton.disabledBackground", "@disabledBackground" );
defaults.put( "ToggleButton.disabledBackground", panelBackground );
// fix Button borders // fix Button
copyIfNotSet( defaults, "Button.focusedBorderColor", "Component.focusedBorderColor", uiKeys ); fixStartEnd( properties, jsonUIKeys, "Button.startBackground", "Button.endBackground", "Button.background" );
defaults.put( "Button.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) ); fixStartEnd( properties, jsonUIKeys, "Button.startBorderColor", "Button.endBorderColor", "Button.borderColor" );
defaults.put( "HelpButton.hoverBorderColor", defaults.get( "Button.focusedBorderColor" ) ); fixStartEnd( properties, jsonUIKeys, "Button.default.startBackground", "Button.default.endBackground", "Button.default.background" );
fixStartEnd( properties, jsonUIKeys, "Button.default.startBorderColor", "Button.default.endBorderColor", "Button.default.borderColor" );
// IDEA uses an SVG icon for the help button, but paints the background with Button.startBackground and Button.endBackground
Object helpButtonBackground = defaults.get( "Button.startBackground" );
Object helpButtonBorderColor = defaults.get( "Button.startBorderColor" );
if( helpButtonBackground == null )
helpButtonBackground = defaults.get( "Button.background" );
if( helpButtonBorderColor == null )
helpButtonBorderColor = defaults.get( "Button.borderColor" );
defaults.put( "HelpButton.background", helpButtonBackground );
defaults.put( "HelpButton.borderColor", helpButtonBorderColor );
defaults.put( "HelpButton.disabledBackground", panelBackground );
defaults.put( "HelpButton.disabledBorderColor", defaults.get( "Button.disabledBorderColor" ) );
defaults.put( "HelpButton.focusedBorderColor", defaults.get( "Button.focusedBorderColor" ) );
defaults.put( "HelpButton.focusedBackground", defaults.get( "Button.focusedBackground" ) );
// IDEA uses TextField.background for editable ComboBox and Spinner // IDEA uses TextField.background for editable ComboBox and Spinner
Object textFieldBackground = get( defaults, themeSpecificDefaults, "TextField.background" ); Object textFieldBackground = get( properties, themeSpecificProps, "TextField.background" );
defaults.put( "ComboBox.editableBackground", textFieldBackground ); put( properties, "ComboBox.editableBackground", textFieldBackground );
defaults.put( "Spinner.background", textFieldBackground ); put( properties, "Spinner.background", textFieldBackground );
// Spinner arrow button always has same colors as ComboBox arrow button
defaults.put( "Spinner.buttonBackground", defaults.get( "ComboBox.buttonEditableBackground" ) );
defaults.put( "Spinner.buttonArrowColor", defaults.get( "ComboBox.buttonArrowColor" ) );
defaults.put( "Spinner.buttonDisabledArrowColor", defaults.get( "ComboBox.buttonDisabledArrowColor" ) );
// some themes specify colors for TextField.background, but forget to specify it for other components // some themes specify colors for TextField.background, but forget to specify it for other components
// (probably because those components are not used in IntelliJ IDEA) // (probably because those components are not used in IntelliJ IDEA)
putAll( defaults, textFieldBackground, putAll( properties, textFieldBackground,
"EditorPane.background", "EditorPane.background",
"FormattedTextField.background", "FormattedTextField.background",
"PasswordField.background", "PasswordField.background",
"TextArea.background", "TextArea.background",
"TextPane.background" "TextPane.background"
); );
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionBackground" ), putAll( properties, get( properties, themeSpecificProps, "TextField.selectionBackground" ),
"EditorPane.selectionBackground", "EditorPane.selectionBackground",
"FormattedTextField.selectionBackground", "FormattedTextField.selectionBackground",
"PasswordField.selectionBackground", "PasswordField.selectionBackground",
"TextArea.selectionBackground", "TextArea.selectionBackground",
"TextPane.selectionBackground" "TextPane.selectionBackground"
); );
putAll( defaults, get( defaults, themeSpecificDefaults, "TextField.selectionForeground" ), putAll( properties, get( properties, themeSpecificProps, "TextField.selectionForeground" ),
"EditorPane.selectionForeground", "EditorPane.selectionForeground",
"FormattedTextField.selectionForeground", "FormattedTextField.selectionForeground",
"PasswordField.selectionForeground", "PasswordField.selectionForeground",
@@ -235,7 +224,7 @@ public class IntelliJTheme
// fix disabled and not-editable backgrounds for text components, combobox and spinner // fix disabled and not-editable backgrounds for text components, combobox and spinner
// (IntelliJ IDEA does not use those colors; instead it used background color of parent) // (IntelliJ IDEA does not use those colors; instead it used background color of parent)
putAll( defaults, panelBackground, putAll( properties, "@disabledBackground",
"ComboBox.disabledBackground", "ComboBox.disabledBackground",
"EditorPane.disabledBackground", "EditorPane.inactiveBackground", "EditorPane.disabledBackground", "EditorPane.inactiveBackground",
"FormattedTextField.disabledBackground", "FormattedTextField.inactiveBackground", "FormattedTextField.disabledBackground", "FormattedTextField.inactiveBackground",
@@ -246,132 +235,148 @@ public class IntelliJTheme
"TextPane.disabledBackground", "TextPane.inactiveBackground" "TextPane.disabledBackground", "TextPane.inactiveBackground"
); );
// fix ToggleButton
if( !uiKeys.contains( "ToggleButton.startBackground" ) && !uiKeys.contains( "*.startBackground" ) )
defaults.put( "ToggleButton.startBackground", defaults.get( "Button.startBackground" ) );
if( !uiKeys.contains( "ToggleButton.endBackground" ) && !uiKeys.contains( "*.endBackground" ) )
defaults.put( "ToggleButton.endBackground", defaults.get( "Button.endBackground" ) );
if( !uiKeys.contains( "ToggleButton.foreground" ) && uiKeys.contains( "Button.foreground" ) )
defaults.put( "ToggleButton.foreground", defaults.get( "Button.foreground" ) );
// fix DesktopPane background (use Panel.background and make it 5% darker/lighter) // fix DesktopPane background (use Panel.background and make it 5% darker/lighter)
Color desktopBackgroundBase = defaults.getColor( "Panel.background" ); put( properties, "Desktop.background", dark ? "lighten($Panel.background,5%)" : "darken($Panel.background,5%)" );
Color desktopBackground = ColorFunctions.applyFunctions( desktopBackgroundBase,
new ColorFunctions.HSLIncreaseDecrease( 2, dark, 5, false, true ) );
defaults.put( "Desktop.background", new ColorUIResource( desktopBackground ) );
// fix List and Table background colors in Material UI Lite themes
if( isMaterialUILite ) {
defaults.put( "List.background", defaults.get( "Tree.background" ) );
defaults.put( "Table.background", defaults.get( "Tree.background" ) );
}
// limit tree row height // limit tree row height
int rowHeight = defaults.getInt( "Tree.rowHeight" ); String rowHeightStr = (String) properties.get( "Tree.rowHeight" );
int rowHeight = (rowHeightStr != null) ? Integer.parseInt( rowHeightStr ) : 0;
if( rowHeight > 22 ) if( rowHeight > 22 )
defaults.put( "Tree.rowHeight", 22 ); put( properties, "Tree.rowHeight", "22" );
// get (and remove) theme specific wildcard replacements, which override all other defaults that end with same suffix // get (and remove) theme specific wildcard replacements, which override all other properties that end with same suffix
HashMap<String, Object> wildcards = new HashMap<>(); HashMap<String, String> wildcardProps = new HashMap<>();
Iterator<Entry<Object, Object>> it = themeSpecificDefaults.entrySet().iterator(); Iterator<Map.Entry<String, String>> it = themeSpecificProps.entrySet().iterator();
while( it.hasNext() ) { while( it.hasNext() ) {
Entry<Object, Object> e = it.next(); Map.Entry<String, String> e = it.next();
String key = (String) e.getKey(); String key = e.getKey();
if( key.startsWith( "*." ) ) { if( key.startsWith( "*." ) ) {
wildcards.put( key.substring( "*.".length() ), e.getValue() ); wildcardProps.put( key, e.getValue() );
it.remove(); it.remove();
} }
} }
// override UI defaults with theme specific wildcard replacements // override properties with theme specific wildcard replacements
if( !wildcards.isEmpty() ) { if( !wildcardProps.isEmpty() ) {
for( Object key : defaults.keySet().toArray() ) { for( Map.Entry<String, String> e : wildcardProps.entrySet() )
int dot; applyWildcard( properties, e.getKey(), e.getValue() );
if( !(key instanceof String) ||
(dot = ((String)key).lastIndexOf( '.' )) < 0 )
continue;
String wildcardKey = ((String)key).substring( dot + 1 );
Object wildcardValue = wildcards.get( wildcardKey );
if( wildcardValue != null )
defaults.put( key, wildcardValue );
}
} }
// apply theme specific UI defaults at the end to allow overwriting // apply theme specific properties at the end to allow overwriting
for( Map.Entry<Object, Object> e : themeSpecificDefaults.entrySet() ) { for( Map.Entry<String, String> e : themeSpecificProps.entrySet() ) {
Object key = e.getKey(); String key = e.getKey();
Object value = e.getValue(); String value = e.getValue();
// append styles to existing styles // append styles to existing styles
if( key instanceof String && ((String)key).startsWith( "[style]" ) ) { if( key.startsWith( "[style]" ) ) {
Object oldValue = defaults.get( key ); String oldValue = (String) properties.get( key );
if( oldValue != null ) if( oldValue != null )
value = oldValue + "; " + value; value = oldValue + "; " + value;
} }
defaults.put( key, value ); put( properties, key, value );
} }
// let Java release memory // let Java release memory
colors = null; jsonColors = null;
ui = null; jsonUI = null;
icons = null; jsonIcons = null;
} }
private Object get( UIDefaults defaults, Map<Object, Object> themeSpecificDefaults, String key ) { private String get( Properties properties, Map<String, String> themeSpecificProps, String key ) {
return themeSpecificDefaults.getOrDefault( key, defaults.get( key ) ); return themeSpecificProps.getOrDefault( key, (String) properties.get( key ) );
} }
private void putAll( UIDefaults defaults, Object value, String... keys ) { private void put( Properties properties, Object key, Object value ) {
if( value != null )
properties.put( key, value );
else
properties.remove( key );
}
private void putAll( Properties properties, Object value, String... keys ) {
for( String key : keys ) for( String key : keys )
defaults.put( key, value ); put( properties, key, value );
} }
private Map<Object, Object> removeThemeSpecificDefaults( UIDefaults defaults ) { private void copyIfSetInJson( Properties properties, Set<String> jsonUIKeys, String destKey, String... srcKeys ) {
// search for theme specific UI defaults keys for( String srcKey : srcKeys ) {
if( jsonUIKeys.contains( srcKey ) ) {
Object value = properties.get( srcKey );
if( value != null ) {
put( properties, destKey, value );
break;
}
}
}
}
private void fixStartEnd( Properties properties, Set<String> jsonUIKeys, String startKey, String endKey, String key ) {
if( jsonUIKeys.contains( startKey ) && jsonUIKeys.contains( endKey ) )
put( properties, key, "$" + startKey );
}
private Map<String, String> removeThemeSpecificProps( Properties properties ) {
// search for theme specific properties keys
ArrayList<String> themeSpecificKeys = new ArrayList<>(); ArrayList<String> themeSpecificKeys = new ArrayList<>();
for( Object key : defaults.keySet() ) { for( Object key : properties.keySet() ) {
if( key instanceof String && ((String)key).startsWith( "{" ) ) if( ((String)key).startsWith( "{" ) )
themeSpecificKeys.add( (String) key ); themeSpecificKeys.add( (String) key );
} }
// remove theme specific UI defaults and remember only those for current theme // special prefixes (priority from highest to lowest)
Map<Object, Object> themeSpecificDefaults = new HashMap<>();
String currentThemePrefix = '{' + name.replace( ' ', '_' ) + '}'; String currentThemePrefix = '{' + name.replace( ' ', '_' ) + '}';
String currentThemeAndAuthorPrefix = '{' + name.replace( ' ', '_' ) + "---" + author.replace( ' ', '_' ) + '}'; String currentThemeAndAuthorPrefix = '{' + name.replace( ' ', '_' ) + "---" + author.replace( ' ', '_' ) + '}';
String currentAuthorPrefix = "{author-" + author.replace( ' ', '_' ) + '}'; String currentAuthorPrefix = "{author-" + author.replace( ' ', '_' ) + '}';
String lightOrDarkPrefix = dark ? "{*-dark}" : "{*-light}";
String allThemesPrefix = "{*}"; String allThemesPrefix = "{*}";
String[] prefixes = { currentThemePrefix, currentThemeAndAuthorPrefix, currentAuthorPrefix, allThemesPrefix }; String[] prefixes = { currentThemePrefix, currentThemeAndAuthorPrefix, currentAuthorPrefix, lightOrDarkPrefix, allThemesPrefix };
// collect values for special prefixes in its own maps
@SuppressWarnings( "unchecked" )
Map<String, String>[] maps = new Map[prefixes.length];
for( int i = 0; i < maps.length; i++ )
maps[i] = new HashMap<>();
// remove theme specific properties and remember only those for current theme
for( String key : themeSpecificKeys ) { for( String key : themeSpecificKeys ) {
Object value = defaults.remove( key ); String value = (String) properties.remove( key );
for( String prefix : prefixes ) { for( int i = 0; i < prefixes.length; i++ ) {
String prefix = prefixes[i];
if( key.startsWith( prefix ) ) { if( key.startsWith( prefix ) ) {
themeSpecificDefaults.put( key.substring( prefix.length() ), value ); maps[i].put( key.substring( prefix.length() ), value );
break; break;
} }
} }
} }
return themeSpecificDefaults; // copy values into single map (from lowest to highest priority)
Map<String, String> themeSpecificProps = new HashMap<>();
for( int i = maps.length - 1; i >= 0; i-- )
themeSpecificProps.putAll( maps[i] );
return themeSpecificProps;
} }
/** /**
* http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#defining-named-colors * http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#defining-named-colors
*/ */
private void loadNamedColors( UIDefaults defaults ) { private void loadNamedColors( Properties properties, Set<String> jsonUIKeys ) {
if( colors == null ) if( jsonColors == null )
return; return;
namedColors = new HashMap<>(); namedColors = new HashMap<>();
for( Map.Entry<String, String> e : colors.entrySet() ) { for( Map.Entry<String, String> e : jsonColors.entrySet() ) {
String value = e.getValue(); String value = e.getValue();
ColorUIResource color = parseColor( value ); if( canParseColor( value ) ) {
if( color != null ) {
String key = e.getKey(); String key = e.getKey();
namedColors.put( key, color ); namedColors.put( key, value );
defaults.put( "ColorPalette." + key, color );
String uiKey = "ColorPalette." + key;
put( properties, uiKey, value );
// this is only necessary for copyIfSetInJson() (used for accent color)
jsonUIKeys.add( uiKey );
} }
} }
} }
@@ -380,7 +385,7 @@ public class IntelliJTheme
* http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#custom-ui-control-colors * http://www.jetbrains.org/intellij/sdk/docs/reference_guide/ui_themes/themes_customize.html#custom-ui-control-colors
*/ */
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
private void apply( String key, Object value, UIDefaults defaults, ArrayList<Object> defaultsKeysCache, Set<String> uiKeys ) { private void apply( String key, Object value, Properties properties, Set<String> jsonUIKeys ) {
if( value instanceof Map ) { if( value instanceof Map ) {
Map<String, Object> map = (Map<String, Object>)value; Map<String, Object> map = (Map<String, Object>)value;
if( map.containsKey( "os.default" ) || map.containsKey( "os.windows" ) || map.containsKey( "os.mac" ) || map.containsKey( "os.linux" ) ) { if( map.containsKey( "os.default" ) || map.containsKey( "os.windows" ) || map.containsKey( "os.mac" ) || map.containsKey( "os.linux" ) ) {
@@ -388,12 +393,12 @@ public class IntelliJTheme
: SystemInfo.isMacOS ? "os.mac" : SystemInfo.isMacOS ? "os.mac"
: SystemInfo.isLinux ? "os.linux" : null; : SystemInfo.isLinux ? "os.linux" : null;
if( osKey != null && map.containsKey( osKey ) ) if( osKey != null && map.containsKey( osKey ) )
apply( key, map.get( osKey ), defaults, defaultsKeysCache, uiKeys ); apply( key, map.get( osKey ), properties, jsonUIKeys );
else if( map.containsKey( "os.default" ) ) else if( map.containsKey( "os.default" ) )
apply( key, map.get( "os.default" ), defaults, defaultsKeysCache, uiKeys ); apply( key, map.get( "os.default" ), properties, jsonUIKeys );
} else { } else {
for( Map.Entry<String, Object> e : map.entrySet() ) for( Map.Entry<String, Object> e : map.entrySet() )
apply( key + '.' + e.getKey(), e.getValue(), defaults, defaultsKeysCache, uiKeys ); apply( key + '.' + e.getKey(), e.getValue(), properties, jsonUIKeys );
} }
} else { } else {
if( "".equals( value ) ) if( "".equals( value ) )
@@ -418,15 +423,15 @@ public class IntelliJTheme
if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) ) if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) )
return; return;
if( uiKeyDoNotOverride.contains( key ) && uiKeys.contains( key ) ) if( uiKeyDoNotOverride.contains( key ) && jsonUIKeys.contains( key ) )
return; return;
uiKeys.add( key ); jsonUIKeys.add( key );
String valueStr = value.toString(); String valueStr = value.toString();
// map named colors // map named colors
Object uiValue = namedColors.get( valueStr ); String uiValue = namedColors.get( valueStr );
// parse value // parse value
if( uiValue == null ) { if( uiValue == null ) {
@@ -445,47 +450,64 @@ public class IntelliJTheme
// parse value // parse value
try { try {
uiValue = UIDefaultsLoader.parseValue( key, valueStr, null ); UIDefaultsLoader.parseValue( key, valueStr, null );
uiValue = valueStr;
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
UIDefaultsLoader.logParseError( key, valueStr, ex, false ); UIDefaultsLoader.logParseError( key, valueStr, ex, true );
return; // ignore invalid value return; // ignore invalid value
} }
} }
if( key.startsWith( "*." ) ) { // wildcards
// wildcard if( applyWildcard( properties, key, uiValue ) )
String tail = key.substring( 1 ); return;
// because we can not iterate over the UI defaults keys while put( properties, key, uiValue );
// modifying UI defaults in the same loop, we have to copy the keys
if( defaultsKeysCache.size() != defaults.size() ) {
defaultsKeysCache.clear();
Enumeration<Object> e = defaults.keys();
while( e.hasMoreElements() )
defaultsKeysCache.add( e.nextElement() );
}
// replace all values in UI defaults that match the wildcard key
for( Object k : defaultsKeysCache ) {
if( k.equals( "Desktop.background" ) ||
k.equals( "DesktopIcon.background" ) ||
k.equals( "TabbedPane.focusColor" ) )
continue;
if( k instanceof String ) {
// support replacing of mapped keys
// (e.g. set ComboBox.buttonEditableBackground to *.background
// because it is mapped from ComboBox.ArrowButton.background)
String km = uiKeyInverseMapping.getOrDefault( k, (String) k );
if( km.endsWith( tail ) && !((String)k).startsWith( "CheckBox.icon." ) )
defaults.put( k, uiValue );
}
}
} else
defaults.put( key, uiValue );
} }
} }
private boolean applyWildcard( Properties properties, String key, String value ) {
if( !key.startsWith( "*." ) )
return false;
String tail = key.substring( 1 );
// because we can not iterate over the properties keys while
// modifying properties in the same loop, we have to copy the keys
String[] keys = properties.keySet().toArray( new String[properties.size()] );
// replace all values in properties that match the wildcard key
for( String k : keys ) {
if( k.startsWith( "*" ) ||
k.startsWith( "@" ) ||
k.startsWith( "HelpButton." ) ||
k.startsWith( "JX" ) ||
k.startsWith( "Jide" ) ||
k.startsWith( "ProgressBar.selection" ) ||
k.startsWith( "TitlePane." ) ||
k.startsWith( "ToggleButton.tab." ) ||
k.equals( "Desktop.background" ) ||
k.equals( "DesktopIcon.background" ) ||
k.equals( "TabbedPane.focusColor" ) ||
k.endsWith( ".hoverBackground" ) ||
k.endsWith( ".pressedBackground" ) )
continue;
// support replacing of mapped keys
// (e.g. set ComboBox.buttonEditableBackground to *.background
// because it is mapped from ComboBox.ArrowButton.background)
String km = uiKeyInverseMapping.getOrDefault( k, k );
if( km.endsWith( tail ) && !k.startsWith( "CheckBox.icon." ) )
put( properties, k, value );
}
// Note: also add wildcards to properties and let UIDefaultsLoader
// process it on BasicLookAndFeel UI defaults
put( properties, key, value );
return true;
}
private String fixColorIfValid( String newColorStr, String colorStr ) { private String fixColorIfValid( String newColorStr, String colorStr ) {
try { try {
// check whether it is valid // check whether it is valid
@@ -497,11 +519,11 @@ public class IntelliJTheme
} }
} }
private void applyColorPalette( UIDefaults defaults ) { private void applyIconsColorPalette( Properties properties ) {
if( icons == null ) if( jsonIcons == null )
return; return;
Object palette = icons.get( "ColorPalette" ); Object palette = jsonIcons.get( "ColorPalette" );
if( !(palette instanceof Map) ) if( !(palette instanceof Map) )
return; return;
@@ -510,44 +532,48 @@ public class IntelliJTheme
for( Map.Entry<String, Object> e : colorPalette.entrySet() ) { for( Map.Entry<String, Object> e : colorPalette.entrySet() ) {
String key = e.getKey(); String key = e.getKey();
Object value = e.getValue(); Object value = e.getValue();
if( key.startsWith( "Checkbox." ) || !(value instanceof String) ) if( key.startsWith( "Checkbox." ) || key.startsWith( "#" ) || !(value instanceof String) )
continue; continue;
if( dark ) if( dark )
key = StringUtils.removeTrailing( key, ".Dark" ); key = StringUtils.removeTrailing( key, ".Dark" );
ColorUIResource color = toColor( (String) value ); String color = toColor( (String) value );
if( color != null ) if( color != null )
defaults.put( key, color ); put( properties, key, color );
} }
} }
private ColorUIResource toColor( String value ) { private String toColor( String value ) {
if( value.startsWith( "##" ) )
value = fixColorIfValid( value.substring( 1 ), value );
// map named colors // map named colors
ColorUIResource color = namedColors.get( value ); String color = namedColors.get( value );
// parse color // parse color
return (color != null) ? color : parseColor( value ); return (color != null) ? color : (canParseColor( value ) ? value : null);
} }
private ColorUIResource parseColor( String value ) { private boolean canParseColor( String value ) {
try { try {
return UIDefaultsLoader.parseColor( value ); return UIDefaultsLoader.parseColor( value ) != null;
} catch( IllegalArgumentException ex ) { } catch( IllegalArgumentException ex ) {
return null; LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to parse color: '" + value + '\'', ex );
return false;
} }
} }
/** /**
* Because IDEA uses SVGs for check boxes and radio buttons, the colors for * Because IDEA uses SVGs for check boxes and radio buttons, the colors for
* these two components are specified in "icons > ColorPalette". * these two components are specified in "icons > ColorPalette".
* FlatLaf uses vector icons and expects colors for the two components in UI defaults. * FlatLaf uses vector icons and expects colors for the two components in properties.
*/ */
private void applyCheckBoxColors( UIDefaults defaults ) { private void applyCheckBoxColors( Properties properties ) {
if( icons == null ) if( jsonIcons == null )
return; return;
Object palette = icons.get( "ColorPalette" ); Object palette = jsonIcons.get( "ColorPalette" );
if( !(palette instanceof Map) ) if( !(palette instanceof Map) )
return; return;
@@ -569,9 +595,9 @@ public class IntelliJTheme
if( !dark && newKey.startsWith( checkBoxIconPrefix ) ) if( !dark && newKey.startsWith( checkBoxIconPrefix ) )
newKey = "CheckBox.icon[filled].".concat( newKey.substring( checkBoxIconPrefix.length() ) ); newKey = "CheckBox.icon[filled].".concat( newKey.substring( checkBoxIconPrefix.length() ) );
ColorUIResource color = toColor( (String) value ); String color = toColor( (String) value );
if( color != null ) { if( color != null ) {
defaults.put( newKey, color ); put( properties, newKey, color );
String key2 = checkboxDuplicateColors.get( key + ".Dark"); String key2 = checkboxDuplicateColors.get( key + ".Dark");
if( key2 != null ) { if( key2 != null ) {
@@ -592,7 +618,7 @@ public class IntelliJTheme
String newKey2 = checkboxKeyMapping.get( key2 ); String newKey2 = checkboxKeyMapping.get( key2 );
if( newKey2 != null ) if( newKey2 != null )
defaults.put( newKey2, color ); put( properties, newKey2, color );
} }
} }
@@ -603,13 +629,13 @@ public class IntelliJTheme
// update hover, pressed and focused colors // update hover, pressed and focused colors
if( checkboxModified ) { if( checkboxModified ) {
// for non-filled checkbox/radiobutton used in dark themes // for non-filled checkbox/radiobutton used in dark themes
defaults.remove( "CheckBox.icon.focusWidth" ); properties.remove( "CheckBox.icon.focusWidth" );
defaults.put( "CheckBox.icon.hoverBorderColor", defaults.get( "CheckBox.icon.focusedBorderColor" ) ); put( properties, "CheckBox.icon.hoverBorderColor", properties.get( "CheckBox.icon.focusedBorderColor" ) );
// for filled checkbox/radiobutton used in light themes // for filled checkbox/radiobutton used in light themes
defaults.remove( "CheckBox.icon[filled].focusWidth" ); properties.remove( "CheckBox.icon[filled].focusWidth" );
defaults.put( "CheckBox.icon[filled].hoverBorderColor", defaults.get( "CheckBox.icon[filled].focusedBorderColor" ) ); put( properties, "CheckBox.icon[filled].hoverBorderColor", properties.get( "CheckBox.icon[filled].focusedBorderColor" ) );
defaults.put( "CheckBox.icon[filled].focusedSelectedBackground", defaults.get( "CheckBox.icon[filled].selectedBackground" ) ); put( properties, "CheckBox.icon[filled].focusedSelectedBackground", properties.get( "CheckBox.icon[filled].selectedBackground" ) );
if( dark ) { if( dark ) {
// IDEA Darcula checkBoxFocused.svg, checkBoxSelectedFocused.svg, // IDEA Darcula checkBoxFocused.svg, checkBoxSelectedFocused.svg,
@@ -623,21 +649,14 @@ public class IntelliJTheme
"CheckBox.icon[filled].focusedSelectedBorderColor", "CheckBox.icon[filled].focusedSelectedBorderColor",
}; };
for( String key : focusedBorderColorKeys ) { for( String key : focusedBorderColorKeys ) {
Color color = defaults.getColor( key ); Object color = properties.get( key );
if( color != null ) { if( color != null )
defaults.put( key, new ColorUIResource( new Color( put( properties, key, "fade(" + color + ", 65%)" );
(color.getRGB() & 0xffffff) | 0xa6000000, true ) ) );
}
} }
} }
} }
} }
private void copyIfNotSet( UIDefaults defaults, String destKey, String srcKey, Set<String> uiKeys ) {
if( !uiKeys.contains( destKey ) )
defaults.put( destKey, defaults.get( srcKey ) );
}
private static final Set<String> uiKeyExcludes; private static final Set<String> uiKeyExcludes;
private static final Set<String> uiKeyDoNotOverride; private static final Set<String> uiKeyDoNotOverride;
/** Rename UI default keys (key --> value). */ /** Rename UI default keys (key --> value). */
@@ -653,26 +672,26 @@ public class IntelliJTheme
uiKeyExcludes = new HashSet<>( Arrays.asList( uiKeyExcludes = new HashSet<>( Arrays.asList(
"ActionButton.", "ActionToolbar.", "ActionsList.", "AppInspector.", "AssignedMnemonic.", "Autocomplete.", "ActionButton.", "ActionToolbar.", "ActionsList.", "AppInspector.", "AssignedMnemonic.", "Autocomplete.",
"AvailableMnemonic.", "AvailableMnemonic.",
"Badge.", "BigSpinner.", "Bookmark.", "BookmarkIcon.", "BookmarkMnemonicAssigned.", "BookmarkMnemonicAvailable.", "Badge.", "Banner.", "BigSpinner.", "Bookmark.", "BookmarkIcon.", "BookmarkMnemonicAssigned.", "BookmarkMnemonicAvailable.",
"BookmarkMnemonicCurrent.", "BookmarkMnemonicIcon.", "Borders.", "Breakpoint.", "BookmarkMnemonicCurrent.", "BookmarkMnemonicIcon.", "Borders.", "Breakpoint.",
"Canvas.", "Code.", "CodeWithMe.", "CombinedDiff.", "ComboBoxButton.", "CompilationCharts.", "Canvas.", "CellEditor.", "Code.", "CodeWithMe.", "ColumnControlButton.", "CombinedDiff.", "ComboBoxButton.",
"CompletionPopup.", "ComplexPopup.", "Content.", "ContextHelp.", "CurrentMnemonic.", "Counter.", "CompilationCharts.", "CompletionPopup.", "ComplexPopup.", "Content.", "ContextHelp.", "CurrentMnemonic.", "Counter.",
"Debugger.", "DebuggerPopup.", "DebuggerTabs.", "DefaultTabs.", "Dialog.", "DialogWrapper.", "Debugger.", "DebuggerPopup.", "DebuggerTabs.", "DefaultTabs.", "Dialog.", "DialogWrapper.",
"DisclosureButton.", "DragAndDrop.", "DisclosureButton.", "DragAndDrop.",
"Editor.", "EditorGroupsTabs.", "EditorTabs.", "Editor.", "EditorGroupsTabs.", "EditorTabs.",
"FileColor.", "FlameGraph.", "Focus.", "FileColor.", "FindPopup.", "FlameGraph.", "Focus.",
"Git.", "Github.", "GotItTooltip.", "Group.", "Gutter.", "GutterTooltip.", "Git.", "Github.", "GotItTooltip.", "Group.", "Gutter.", "GutterTooltip.",
"HeaderColor.", "HelpTooltip.", "Hg.", "HeaderColor.", "HelpTooltip.", "Hg.",
"IconBadge.", "InformationHint.", "InplaceRefactoringPopup.", "IconBadge.", "InformationHint.", "InlineBanner.", "InplaceRefactoringPopup.",
"Lesson.", "LineProfiler.", "Link.", "LiveIndicator.", "Lesson.", "LineProfiler.", "Link.", "LiveIndicator.",
"MainMenu.", "MainToolbar.", "MemoryIndicator.", "MlModelBinding.", "MnemonicIcon.", "MainMenu.", "MainToolbar.", "MainWindow.", "MemoryIndicator.", "MlModelBinding.", "MnemonicIcon.",
"NavBar.", "NewClass.", "NewPSD.", "Notification.", "Notifications.", "NotificationsToolwindow.", "NavBar.", "NewClass.", "NewPSD.", "Notification.", "Notifications.", "NotificationsToolwindow.",
"OnePixelDivider.", "OptionButton.", "Outline.", "OnePixelDivider.", "OptionButton.", "Outline.",
"ParameterInfo.", "Plugins.", "Profiler.", "ProgressIcon.", "PsiViewer.", "ParameterInfo.", "PresentationAssistant.", "Plugins.", "Profiler.", "ProgressIcon.", "PsiViewer.",
"ReviewList.", "RunWidget.", "Resizable.", "Review.", "ReviewList.", "RunToolbar.", "RunWidget.",
"ScreenView.", "SearchEverywhere.", "SearchFieldWithExtension.", "SearchMatch.", "SearchOption.", "ScreenView.", "SearchEverywhere.", "SearchFieldWithExtension.", "SearchMatch.", "SearchOption.",
"SearchResults.", "SegmentedButton.", "Settings.", "SidePanel.", "Space.", "SpeedSearch.", "StateWidget.", "SearchResults.", "SegmentedButton.", "Settings.", "SidePanel.", "Space.", "SpeedSearch.", "StateWidget.",
"StatusBar.", "StatusBar.", "StripeToolbar.",
"Tag.", "TipOfTheDay.", "ToolbarComboWidget.", "ToolWindow.", "TrialWidget.", "Tag.", "TipOfTheDay.", "ToolbarComboWidget.", "ToolWindow.", "TrialWidget.",
"UIDesigner.", "UnattendedHostStatus.", "UIDesigner.", "UnattendedHostStatus.",
"ValidationTooltip.", "VersionControl.", "ValidationTooltip.", "VersionControl.",
@@ -689,6 +708,9 @@ public class IntelliJTheme
"TabbedPane.selectedForeground" "TabbedPane.selectedForeground"
) ); ) );
// Button
uiKeyMapping.put( "Button.minimumSize", "" ); // ignore (used in Material Theme UI Lite)
// ComboBox // ComboBox
uiKeyMapping.put( "ComboBox.background", "" ); // ignore uiKeyMapping.put( "ComboBox.background", "" ); // ignore
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
@@ -697,8 +719,6 @@ public class IntelliJTheme
uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" ); uiKeyMapping.put( "ComboBox.ArrowButton.disabledIconColor", "ComboBox.buttonDisabledArrowColor" );
uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" ); uiKeyMapping.put( "ComboBox.ArrowButton.iconColor", "ComboBox.buttonArrowColor" );
uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" ); uiKeyMapping.put( "ComboBox.ArrowButton.nonEditableBackground", "ComboBox.buttonBackground" );
uiKeyCopying.put( "ComboBox.buttonSeparatorColor", "Component.borderColor" );
uiKeyCopying.put( "ComboBox.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
// Component // Component
uiKeyMapping.put( "Component.inactiveErrorFocusColor", "Component.error.borderColor" ); uiKeyMapping.put( "Component.inactiveErrorFocusColor", "Component.error.borderColor" );
@@ -706,16 +726,16 @@ public class IntelliJTheme
uiKeyMapping.put( "Component.inactiveWarningFocusColor", "Component.warning.borderColor" ); uiKeyMapping.put( "Component.inactiveWarningFocusColor", "Component.warning.borderColor" );
uiKeyMapping.put( "Component.warningFocusColor", "Component.warning.focusedBorderColor" ); uiKeyMapping.put( "Component.warningFocusColor", "Component.warning.focusedBorderColor" );
// Label
uiKeyMapping.put( "Label.disabledForegroundColor", "" ); // ignore (used in Material Theme UI Lite)
// Link // Link
uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" ); uiKeyMapping.put( "Link.activeForeground", "Component.linkColor" );
// Menu // Menu
uiKeyMapping.put( "Menu.border", "Menu.margin" ); uiKeyMapping.put( "Menu.border", "Menu.margin" );
uiKeyMapping.put( "MenuItem.border", "MenuItem.margin" ); uiKeyMapping.put( "MenuItem.border", "MenuItem.margin" );
uiKeyCopying.put( "CheckBoxMenuItem.margin", "MenuItem.margin" );
uiKeyCopying.put( "RadioButtonMenuItem.margin", "MenuItem.margin" );
uiKeyMapping.put( "PopupMenu.border", "PopupMenu.borderInsets" ); uiKeyMapping.put( "PopupMenu.border", "PopupMenu.borderInsets" );
uiKeyCopying.put( "MenuItem.underlineSelectionColor", "TabbedPane.underlineColor" );
// IDEA uses List.selectionBackground also for menu selection // IDEA uses List.selectionBackground also for menu selection
uiKeyCopying.put( "Menu.selectionBackground", "List.selectionBackground" ); uiKeyCopying.put( "Menu.selectionBackground", "List.selectionBackground" );
@@ -723,13 +743,11 @@ public class IntelliJTheme
uiKeyCopying.put( "CheckBoxMenuItem.selectionBackground", "List.selectionBackground" ); uiKeyCopying.put( "CheckBoxMenuItem.selectionBackground", "List.selectionBackground" );
uiKeyCopying.put( "RadioButtonMenuItem.selectionBackground", "List.selectionBackground" ); uiKeyCopying.put( "RadioButtonMenuItem.selectionBackground", "List.selectionBackground" );
// ProgressBar // ProgressBar: IDEA uses ProgressBar.trackColor and ProgressBar.progressColor
uiKeyMapping.put( "ProgressBar.background", "" ); // ignore uiKeyMapping.put( "ProgressBar.background", "" ); // ignore
uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore uiKeyMapping.put( "ProgressBar.foreground", "" ); // ignore
uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" ); uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" );
uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" ); uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" );
uiKeyCopying.put( "ProgressBar.selectionForeground", "ProgressBar.background" );
uiKeyCopying.put( "ProgressBar.selectionBackground", "ProgressBar.foreground" );
// ScrollBar // ScrollBar
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" ); uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
@@ -739,34 +757,30 @@ public class IntelliJTheme
uiKeyMapping.put( "Separator.separatorColor", "Separator.foreground" ); uiKeyMapping.put( "Separator.separatorColor", "Separator.foreground" );
// Slider // Slider
uiKeyMapping.put( "Slider.buttonColor", "Slider.thumbColor" );
uiKeyMapping.put( "Slider.buttonBorderColor", "" ); // ignore
uiKeyMapping.put( "Slider.thumb", "" ); // ignore (used in Material Theme UI Lite)
uiKeyMapping.put( "Slider.track", "" ); // ignore (used in Material Theme UI Lite)
uiKeyMapping.put( "Slider.trackDisabled", "" ); // ignore (used in Material Theme UI Lite)
uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite) uiKeyMapping.put( "Slider.trackWidth", "" ); // ignore (used in Material Theme UI Lite)
uiKeyCopying.put( "Slider.trackValueColor", "ProgressBar.foreground" );
uiKeyCopying.put( "Slider.thumbColor", "ProgressBar.foreground" );
uiKeyCopying.put( "Slider.trackColor", "ProgressBar.background" );
// Spinner
uiKeyCopying.put( "Spinner.buttonSeparatorColor", "Component.borderColor" );
uiKeyCopying.put( "Spinner.buttonDisabledSeparatorColor", "Component.disabledBorderColor" );
// TabbedPane // TabbedPane
uiKeyMapping.put( "DefaultTabs.underlinedTabBackground", "TabbedPane.selectedBackground" ); uiKeyMapping.put( "DefaultTabs.underlinedTabBackground", "TabbedPane.selectedBackground" );
uiKeyMapping.put( "DefaultTabs.underlinedTabForeground", "TabbedPane.selectedForeground" ); uiKeyMapping.put( "DefaultTabs.underlinedTabForeground", "TabbedPane.selectedForeground" );
uiKeyMapping.put( "DefaultTabs.inactiveUnderlineColor", "TabbedPane.inactiveUnderlineColor" ); uiKeyMapping.put( "DefaultTabs.inactiveUnderlineColor", "TabbedPane.inactiveUnderlineColor" );
uiKeyMapping.put( "TabbedPane.tabAreaInsets", "" ); // ignore (used in Material Theme UI Lite)
// TableHeader
uiKeyMapping.put( "TableHeader.cellBorder", "" ); // ignore (used in Material Theme UI Lite)
uiKeyMapping.put( "TableHeader.height", "" ); // ignore (used in Material Theme UI Lite)
// TitlePane // TitlePane
uiKeyCopying.put( "TitlePane.inactiveBackground", "TitlePane.background" );
uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" ); uiKeyMapping.put( "TitlePane.infoForeground", "TitlePane.foreground" );
uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" ); uiKeyMapping.put( "TitlePane.inactiveInfoForeground", "TitlePane.inactiveForeground" );
for( Map.Entry<String, String> e : uiKeyMapping.entrySet() ) for( Map.Entry<String, String> e : uiKeyMapping.entrySet() )
uiKeyInverseMapping.put( e.getValue(), e.getKey() ); uiKeyInverseMapping.put( e.getValue(), e.getKey() );
uiKeyCopying.put( "ToggleButton.tab.underlineColor", "TabbedPane.underlineColor" );
uiKeyCopying.put( "ToggleButton.tab.disabledUnderlineColor", "TabbedPane.disabledUnderlineColor" );
uiKeyCopying.put( "ToggleButton.tab.selectedBackground", "TabbedPane.selectedBackground" );
uiKeyCopying.put( "ToggleButton.tab.hoverBackground", "TabbedPane.hoverColor" );
uiKeyCopying.put( "ToggleButton.tab.focusBackground", "TabbedPane.focusColor" );
checkboxKeyMapping.put( "Checkbox.Background.Default", "CheckBox.icon.background" ); checkboxKeyMapping.put( "Checkbox.Background.Default", "CheckBox.icon.background" );
checkboxKeyMapping.put( "Checkbox.Background.Disabled", "CheckBox.icon.disabledBackground" ); checkboxKeyMapping.put( "Checkbox.Background.Disabled", "CheckBox.icon.disabledBackground" );
checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" ); checkboxKeyMapping.put( "Checkbox.Border.Default", "CheckBox.icon.borderColor" );
@@ -819,17 +833,15 @@ public class IntelliJTheme
} }
@Override @Override
void applyAdditionalDefaults( UIDefaults defaults ) { void applyAdditionalProperties( Properties properties ) {
theme.applyProperties( defaults ); theme.applyProperties( properties );
} }
@Override @Override
protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() { protected ArrayList<Class<?>> getLafClassesForDefaultsLoading() {
ArrayList<Class<?>> lafClasses = new ArrayList<>(); ArrayList<Class<?>> lafClasses = UIDefaultsLoader.getLafClassesForDefaultsLoading( getClass() );
lafClasses.add( FlatLaf.class ); lafClasses.add( 1, theme.dark ? FlatDarkLaf.class : FlatLightLaf.class );
lafClasses.add( theme.dark ? FlatDarkLaf.class : FlatLightLaf.class ); lafClasses.add( 2, theme.dark ? FlatDarculaLaf.class : FlatIntelliJLaf.class );
lafClasses.add( theme.dark ? FlatDarculaLaf.class : FlatIntelliJLaf.class );
lafClasses.add( ThemeLaf.class );
return lafClasses; return lafClasses;
} }
} }

View File

@@ -41,6 +41,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
@@ -85,15 +86,14 @@ class UIDefaultsLoader
private static final String WILDCARD_PREFIX = "*."; private static final String WILDCARD_PREFIX = "*.";
static final String KEY_VARIABLES = "FlatLaf.internal.variables"; static final String KEY_VARIABLES = "FlatLaf.internal.variables";
static final String KEY_PROPERTIES = "FlatLaf.internal.properties";
private static int parseColorDepth; private static int parseColorDepth;
private static Map<String, ColorUIResource> systemColorCache; private static Map<String, ColorUIResource> systemColorCache;
private static final SoftCache<String, Object> fontCache = new SoftCache<>(); private static final SoftCache<String, Object> fontCache = new SoftCache<>();
static void loadDefaultsFromProperties( Class<?> lookAndFeelClass, List<FlatDefaultsAddon> addons, static ArrayList<Class<?>> getLafClassesForDefaultsLoading( Class<?> lookAndFeelClass ) {
Properties additionalDefaults, boolean dark, UIDefaults defaults )
{
// determine classes in class hierarchy in reverse order // determine classes in class hierarchy in reverse order
ArrayList<Class<?>> lafClasses = new ArrayList<>(); ArrayList<Class<?>> lafClasses = new ArrayList<>();
for( Class<?> lafClass = lookAndFeelClass; for( Class<?> lafClass = lookAndFeelClass;
@@ -102,12 +102,11 @@ class UIDefaultsLoader
{ {
lafClasses.add( 0, lafClass ); lafClasses.add( 0, lafClass );
} }
return lafClasses;
loadDefaultsFromProperties( lafClasses, addons, additionalDefaults, dark, defaults );
} }
static void loadDefaultsFromProperties( List<Class<?>> lafClasses, List<FlatDefaultsAddon> addons, static void loadDefaultsFromProperties( List<Class<?>> lafClasses, List<FlatDefaultsAddon> addons,
Properties additionalDefaults, boolean dark, UIDefaults defaults ) Consumer<Properties> intellijThemesHook, Properties additionalDefaults, boolean dark, UIDefaults defaults )
{ {
try { try {
// temporary cache system colors while loading defaults, // temporary cache system colors while loading defaults,
@@ -142,6 +141,10 @@ class UIDefaultsLoader
addonClassLoaders.add( addonClassLoader ); addonClassLoaders.add( addonClassLoader );
} }
// apply IntelliJ themes properties
if( intellijThemesHook != null )
intellijThemesHook.accept( properties );
// load custom properties files (usually provided by applications) // load custom properties files (usually provided by applications)
List<Object> customDefaultsSources = FlatLaf.getCustomDefaultsSources(); List<Object> customDefaultsSources = FlatLaf.getCustomDefaultsSources();
int size = (customDefaultsSources != null) ? customDefaultsSources.size() : 0; int size = (customDefaultsSources != null) ? customDefaultsSources.size() : 0;
@@ -287,6 +290,15 @@ class UIDefaultsLoader
// remember variables in defaults to allow using them in styles // remember variables in defaults to allow using them in styles
defaults.put( KEY_VARIABLES, variables ); defaults.put( KEY_VARIABLES, variables );
// remember properties (for testing)
if( FlatSystemProperties.getBoolean( KEY_PROPERTIES, false ) ) {
Properties properties2 = new Properties();
properties2.putAll( properties );
for( Map.Entry<String, String> e : wildcards.entrySet() )
properties2.put( WILDCARD_PREFIX + e.getKey(), e.getValue() );
defaults.put( KEY_PROPERTIES, properties2 );
}
// clear/disable system color cache // clear/disable system color cache
systemColorCache = null; systemColorCache = null;
} catch( IOException ex ) { } catch( IOException ex ) {

View File

@@ -61,7 +61,6 @@ Component.arrowType = triangle
#---- ProgressBar ---- #---- ProgressBar ----
ProgressBar.foreground = darken(@foreground,10%) ProgressBar.foreground = darken(@foreground,10%)
ProgressBar.selectionForeground = @background
#---- RadioButton ---- #---- RadioButton ----

View File

@@ -21,27 +21,41 @@
# - https://www.formdev.com/flatlaf/properties-files/ # - https://www.formdev.com/flatlaf/properties-files/
# - https://www.formdev.com/flatlaf/how-to-customize/ # - https://www.formdev.com/flatlaf/how-to-customize/
# #
# Properties in this file are applied in following order:
# 1. properties without '{...}' and without '[...]' prefix
# 2. properties specified in .theme.json file
# 3. properties starting with '{*}'
# 4. properties starting with '{*-light}' or '{*-dark}'
# 5. properties starting with '{author-<author>}',
# where '<author>' is replaced with "author" value from .theme.json file
# 6. properties starting with '{<name>---<author>}',
# where '<name>' and '<author>' are replaced with "name" and "author" values from .theme.json file
# 7. properties starting with '{<name>}',
# where '<name>' is replaced with "name" value from .theme.json file
# 8. properties with '[...]' prefix
#
#---- system colors ---- #---- system colors ----
# fix (most) system colors because they are usually not set in .json files # fix (most) system colors because they are usually not set in .json files
desktop = lazy(TextField.background) desktop = $TextField.background
activeCaptionText = lazy(TextField.foreground) activeCaptionText = $TextField.foreground
inactiveCaptionText = lazy(TextField.foreground) inactiveCaptionText = $TextField.foreground
window = lazy(Panel.background) window = $Panel.background
windowBorder = lazy(TextField.foreground) windowBorder = $TextField.foreground
windowText = lazy(TextField.foreground) windowText = $TextField.foreground
menu = lazy(Menu.background) menu = $Menu.background
menuText = lazy(Menu.foreground) menuText = $Menu.foreground
text = lazy(TextField.background) text = $TextField.background
textText = lazy(TextField.foreground) textText = $TextField.foreground
textHighlight = lazy(TextField.selectionBackground) textHighlight = $TextField.selectionBackground
textHighlightText = lazy(TextField.selectionForeground) textHighlightText = $TextField.selectionForeground
textInactiveText = lazy(TextField.inactiveForeground) textInactiveText = $TextField.inactiveForeground
control = lazy(Panel.background) control = $Panel.background
controlText = lazy(TextField.foreground) controlText = $TextField.foreground
info = lazy(ToolTip.background) info = $ToolTip.background
infoText = lazy(ToolTip.foreground) infoText = $ToolTip.foreground
#---- variables ---- #---- variables ----
@@ -49,26 +63,13 @@ infoText = lazy(ToolTip.foreground)
# make sure that accent color (set via FlatLaf.setSystemColorGetter()) is ignored # make sure that accent color (set via FlatLaf.setSystemColorGetter()) is ignored
@accentColor = null @accentColor = null
# use same accent color for checkmark, slider, tab underline, etc.
@accentBase2Color = @accentBaseColor
# use fixed color because it is used in borders # use fixed color because it is used in borders
@cellFocusColor = #222 @cellFocusColor = #222
#---- Button ----
Button.startBackground = $Button.background
Button.endBackground = $Button.background
Button.startBorderColor = $Button.borderColor
Button.endBorderColor = $Button.borderColor
Button.default.startBackground = $Button.default.background
Button.default.endBackground = $Button.default.background
Button.default.startBorderColor = $Button.default.borderColor
Button.default.endBorderColor = $Button.default.borderColor
Button.hoverBorderColor = null
Button.default.hoverBorderColor = null
#---- CheckBoxMenuItem ---- #---- CheckBoxMenuItem ----
# colors from intellij/checkmark.svg and darcula/checkmark.svg # colors from intellij/checkmark.svg and darcula/checkmark.svg
@@ -76,19 +77,19 @@ Button.default.hoverBorderColor = null
[dark]CheckBoxMenuItem.icon.checkmarkColor=#fff9 [dark]CheckBoxMenuItem.icon.checkmarkColor=#fff9
#---- Component ----
Component.accentColor = lazy(ProgressBar.foreground)
#---- HelpButton ----
HelpButton.hoverBorderColor = null
#---- Slider ---- #---- Slider ----
Slider.focusedColor = fade($Component.focusColor,40%,derived) # this "reverses" definition in FlatLightLaf/FlatDarkLaf.properties
Slider.trackValueColor = $Slider.thumbColor
Slider.thumbColor = @accentSliderColor
#---- Spinner ----
# Spinner arrow button always has same colors as ComboBox arrow button
Spinner.buttonBackground = $ComboBox.buttonEditableBackground
Spinner.buttonArrowColor = $ComboBox.buttonArrowColor
Spinner.buttonDisabledArrowColor = $ComboBox.buttonDisabledArrowColor
#---- TabbedPane ---- #---- TabbedPane ----
@@ -100,10 +101,9 @@ Slider.focusedColor = fade($Component.focusColor,40%,derived)
#---- ToggleButton ---- #---- ToggleButton ----
ToggleButton.startBackground = $ToggleButton.background {*}ToggleButton.background = $Button.background
ToggleButton.endBackground = $ToggleButton.background {*-dark}ToggleButton.selectedBackground = lighten($ToggleButton.background,15%,derived)
[dark]ToggleButton.selectedBackground = lighten($ToggleButton.background,15%,derived) {*-dark}ToggleButton.disabledSelectedBackground = lighten($ToggleButton.background,5%,derived)
[dark]ToggleButton.disabledSelectedBackground = lighten($ToggleButton.background,5%,derived)
#---- theme specific ---- #---- theme specific ----
@@ -112,343 +112,434 @@ ToggleButton.endBackground = $ToggleButton.background
@ijMenuCheckBackgroundL20 = lighten(@selectionBackground,20%,derived noAutoInverse) @ijMenuCheckBackgroundL20 = lighten(@selectionBackground,20%,derived noAutoInverse)
@ijMenuCheckBackgroundD10 = darken(@selectionBackground,10%,derived noAutoInverse) @ijMenuCheckBackgroundD10 = darken(@selectionBackground,10%,derived noAutoInverse)
@ijTextBackgroundL3 = lighten(Panel.background,3%,lazy) @ijSeparatorLight = shade(@background,15%)
@ijTextBackgroundL4 = lighten(Panel.background,4%,lazy) @ijSeparatorDark = tint(@background,25%)
{Arc_Theme}CheckBoxMenuItem.foreground = lazy(MenuItem.foreground) @ijTextBackgroundL3 = lighten($Panel.background,3%)
{Arc_Theme}PopupMenu.foreground = lazy(MenuItem.foreground) @ijTextBackgroundL4 = lighten($Panel.background,4%)
{Arc_Theme}RadioButtonMenuItem.foreground = lazy(MenuItem.foreground)
{Arc_Theme}ProgressBar.selectionBackground = #000
{Arc_Theme}ProgressBar.selectionForeground = #fff
{Arc_Theme}List.selectionInactiveForeground = #fff
{Arc_Theme}Table.selectionInactiveForeground = #fff
{Arc_Theme}Tree.selectionInactiveForeground = #fff
{Arc_Theme_-_Orange}CheckBoxMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme}@selectionInactiveForeground = @selectionForeground
{Arc_Theme_-_Orange}PopupMenu.foreground = lazy(MenuItem.foreground) {Arc_Theme}CheckBoxMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_-_Orange}RadioButtonMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme}PopupMenu.foreground = $MenuItem.foreground
{Arc_Theme_-_Orange}ProgressBar.selectionBackground = #000 {Arc_Theme}RadioButtonMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_-_Orange}ProgressBar.selectionForeground = #fff
{Arc_Theme_-_Orange}List.selectionInactiveForeground = #fff
{Arc_Theme_-_Orange}Table.selectionInactiveForeground = #fff
{Arc_Theme_-_Orange}Tree.selectionInactiveForeground = #fff
{Arc_Theme_Dark}CheckBoxMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme_-_Orange}@selectionInactiveForeground = @selectionForeground
{Arc_Theme_Dark}PopupMenu.foreground = lazy(MenuItem.foreground) {Arc_Theme_-_Orange}CheckBoxMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_Dark}RadioButtonMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme_-_Orange}PopupMenu.foreground = $MenuItem.foreground
{Arc_Theme_Dark}ProgressBar.selectionBackground = #ddd {Arc_Theme_-_Orange}RadioButtonMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_Dark}ProgressBar.selectionForeground = #ddd
{Arc_Theme_Dark}ToolBar.separatorColor = lazy(Separator.foreground)
{Arc_Theme_Dark_-_Orange}CheckBoxMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme_Dark}CheckBoxMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_Dark_-_Orange}PopupMenu.foreground = lazy(MenuItem.foreground) {Arc_Theme_Dark}PopupMenu.foreground = $MenuItem.foreground
{Arc_Theme_Dark_-_Orange}RadioButtonMenuItem.foreground = lazy(MenuItem.foreground) {Arc_Theme_Dark}RadioButtonMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_Dark_-_Orange}ProgressBar.selectionBackground = #ddd {Arc_Theme_Dark}ToolBar.background = @background
{Arc_Theme_Dark_-_Orange}CheckBoxMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_Dark_-_Orange}PopupMenu.foreground = $MenuItem.foreground
{Arc_Theme_Dark_-_Orange}ProgressBar.selectionForeground = #fff {Arc_Theme_Dark_-_Orange}ProgressBar.selectionForeground = #fff
{Arc_Theme_Dark_-_Orange}ToolBar.separatorColor = lazy(Separator.foreground) {Arc_Theme_Dark_-_Orange}RadioButtonMenuItem.foreground = $MenuItem.foreground
{Arc_Theme_Dark_-_Orange}ToolBar.background = @background
{Carbon}Table.selectionBackground = lazy(List.selectionBackground) {Carbon}Separator.foreground = @ijSeparatorDark
{Carbon}Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Carbon}ToolBar.separatorColor = $Separator.foreground
{Carbon}Table.selectionBackground = $List.selectionBackground
{Carbon}TextField.background = @ijTextBackgroundL4 {Carbon}TextField.background = @ijTextBackgroundL4
{Cobalt_2}Component.accentColor = lazy(Component.focusColor) {Cobalt_2}@accentBaseColor = $ColorPalette.hue3
{Cobalt_2}CheckBox.icon.background = #002946 {Cobalt_2}CheckBox.icon.background = @background
{Cobalt_2}CheckBox.icon.checkmarkColor = #002946
{Cobalt_2}MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {Cobalt_2}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
{Cobalt_2}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {Cobalt_2}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
{Cobalt_2}ComboBox.background = @ijTextBackgroundL3 {Cobalt_2}ComboBox.background = @ijTextBackgroundL3
{Cobalt_2}ComboBox.buttonBackground = @ijTextBackgroundL3 {Cobalt_2}Slider.thumbColor = $ProgressBar.foreground
{Cobalt_2}Slider.disabledTrackColor = $Separator.foreground
{Cobalt_2}TextField.background = @ijTextBackgroundL3 {Cobalt_2}TextField.background = @ijTextBackgroundL3
{Cobalt_2}Table.background = lazy(List.background) {Cobalt_2}Table.background = $List.background
{Cobalt_2}Tree.background = lazy(List.background) {Cobalt_2}Tree.background = $List.background
{Cyan_light}@disabledForeground = tint(@foreground,30%)
{Cyan_light}*.disabledText = @disabledForeground
{Cyan_light}*.disabledForeground = @disabledForeground
{Cyan_light}*.inactiveForeground = @disabledForeground
{Cyan_light}Button.background = @buttonBackground
{Cyan_light}MenuItem.checkBackground = @ijMenuCheckBackgroundL20 {Cyan_light}MenuItem.checkBackground = @ijMenuCheckBackgroundL20
{Cyan_light}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20 {Cyan_light}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
{Dark_Flat_Theme}*.inactiveForeground = #808080 {Dark_Flat_Theme}@accentBaseColor = $TabbedPane.underlineColor
{Dark_Flat_Theme}Component.accentColor = lazy(List.selectionBackground) {Dark_Flat_Theme}@disabledForeground = #808080
{Dark_Flat_Theme}*.disabledText = @disabledForeground
{Dark_Flat_Theme}*.disabledForeground = @disabledForeground
{Dark_Flat_Theme}*.inactiveForeground = @disabledForeground
{Dark_Flat_Theme}TableHeader.background = #3B3B3B {Dark_Flat_Theme}TableHeader.background = #3B3B3B
{Dark_Flat_Theme}TextPane.foreground = lazy(TextField.foreground) {Dark_Flat_Theme}CheckBoxMenuItem.selectionForeground = $MenuItem.selectionForeground
{Dark_Flat_Theme}CheckBoxMenuItem.selectionForeground = lazy(MenuItem.selectionForeground) {Dark_Flat_Theme}ComboBox.background = $TextField.background
{Dark_Flat_Theme}List.selectionForeground = lazy(Tree.selectionForeground) {Dark_Flat_Theme}ComboBox.buttonBackground = $ComboBox.background
{Dark_Flat_Theme}RadioButtonMenuItem.selectionForeground = lazy(MenuItem.selectionForeground) {Dark_Flat_Theme}List.selectionForeground = $Tree.selectionForeground
{Dark_Flat_Theme}Separator.foreground = lazy(ToolBar.separatorColor) {Dark_Flat_Theme}ProgressBar.selectionForeground = @foreground
{Dark_Flat_Theme}RadioButtonMenuItem.selectionForeground = $MenuItem.selectionForeground
{Dark_Flat_Theme}Separator.foreground = @ijSeparatorDark
{Dark_Flat_Theme}Slider.trackColor = $ProgressBar.background
{Dark_Flat_Theme}Slider.thumbColor = fade($ProgressBar.foreground,100%)
{Dark_Flat_Theme}TextPane.foreground = $TextField.foreground
{Dark_Flat_Theme}ToggleButton.foreground = $Button.foreground
{Dark_purple}Slider.focusedColor = fade($Component.focusColor,70%,derived) {Dracula---Zihan_Ma}CheckBox.icon.background = @background
{Dracula---Zihan_Ma}ComboBox.selectionBackground = $List.selectionBackground
{Dracula---Zihan_Ma}Component.accentColor = lazy(Component.focusColor)
{Dracula---Zihan_Ma}ComboBox.selectionBackground = lazy(List.selectionBackground)
{Dracula---Zihan_Ma}ProgressBar.selectionBackground = #fff {Dracula---Zihan_Ma}ProgressBar.selectionBackground = #fff
{Dracula---Zihan_Ma}ProgressBar.selectionForeground = #fff {Dracula---Zihan_Ma}ProgressBar.selectionForeground = #fff
{Dracula---Zihan_Ma}Slider.trackColor = $?ColorPalette.selectionBackground
{Dracula---Zihan_Ma}ToggleButton.foreground = $Button.foreground
{Gradianto_Dark_Fuchsia}*.selectionBackground = #8452a7
{Gradianto_Dark_Fuchsia}*.selectionInactiveBackground = #562C6A
{Gradianto_Dark_Fuchsia}MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {Gradianto_Dark_Fuchsia}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
{Gradianto_Dark_Fuchsia}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {Gradianto_Dark_Fuchsia}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
{Gradianto_Dark_Fuchsia}TextField.background = @ijTextBackgroundL4 {Gradianto_Dark_Fuchsia}TextField.background = @ijTextBackgroundL4
{Gradianto_Dark_Fuchsia}Tree.background = lazy(List.background) {Gradianto_Dark_Fuchsia}Tree.background = $List.background
{Gradianto_Dark_Fuchsia}Separator.foreground = lazy(ScrollBar.track) {Gradianto_Dark_Fuchsia}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Gradianto_Dark_Fuchsia}ToolBar.separatorColor = lazy(ScrollBar.track) {Gradianto_Dark_Fuchsia}Separator.foreground = @ijSeparatorDark
{Gradianto_Dark_Fuchsia}ProgressBar.background = lazy(ScrollBar.track) {Gradianto_Dark_Fuchsia}ToolBar.separatorColor = $Separator.foreground
{Gradianto_Dark_Fuchsia}Slider.trackColor = lazy(ScrollBar.track) {Gradianto_Dark_Fuchsia}ProgressBar.background = $ScrollBar.track
{Gradianto_Dark_Fuchsia}Slider.trackColor = $ScrollBar.track
{Gradianto_Deep_Ocean}Separator.foreground = @ijSeparatorDark
{Gradianto_Deep_Ocean}ToolBar.separatorColor = $Separator.foreground
{Gradianto_Deep_Ocean}TextField.background = @ijTextBackgroundL3 {Gradianto_Deep_Ocean}TextField.background = @ijTextBackgroundL3
{Gradianto_Deep_Ocean}Tree.background = lazy(List.background) {Gradianto_Deep_Ocean}Tree.background = $List.background
{Gradianto_Midnight_Blue}ScrollBar.thumb = #533B6B {Gradianto_Midnight_Blue}ScrollBar.thumb = #533B6B
{Gradianto_Midnight_Blue}Table.selectionForeground = lazy(List.selectionForeground) {Gradianto_Midnight_Blue}Separator.foreground = @ijSeparatorDark
{Gradianto_Midnight_Blue}ToolBar.separatorColor = $Separator.foreground
{Gradianto_Midnight_Blue}Table.selectionForeground = $List.selectionForeground
{Gradianto_Midnight_Blue}TextField.background = @ijTextBackgroundL4 {Gradianto_Midnight_Blue}TextField.background = @ijTextBackgroundL4
{Gradianto_Midnight_Blue}Tree.background = lazy(List.background) {Gradianto_Midnight_Blue}Tree.background = $List.background
{Gradianto_Nature_Green}Table.selectionForeground = lazy(List.selectionForeground) {Gradianto_Nature_Green}Separator.foreground = @ijSeparatorDark
{Gradianto_Nature_Green}ToolBar.separatorColor = $Separator.foreground
{Gradianto_Nature_Green}Table.selectionForeground = $List.selectionForeground
{Gradianto_Nature_Green}TextField.background = @ijTextBackgroundL4 {Gradianto_Nature_Green}TextField.background = @ijTextBackgroundL4
{Gray}Separator.foreground = lazy(Slider.trackColor) {Gray}@disabledForeground = tint(@foreground,40%)
{Gray}ToolBar.separatorColor = lazy(Slider.trackColor) {Gray}*.disabledText = @disabledForeground
{Gray}*.disabledForeground = @disabledForeground
{Gray}*.inactiveForeground = @disabledForeground
{Gray}Button.background = @buttonBackground
{Gray}Separator.foreground = @ijSeparatorLight
{Gray}ToolBar.separatorColor = $Separator.foreground
{Gruvbox_Dark_Hard}Component.accentColor = lazy(TabbedPane.underlineColor) {Gruvbox_Dark_Hard}@accentBaseColor = #4B6EAF
{Gruvbox_Dark_Hard}ToggleButton.selectedBackground = $ToggleButton.selectedBackground
{Gruvbox_Dark_Hard}ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground
{Gruvbox_Dark_Hard}ComboBox.background = @ijTextBackgroundL3 {Gruvbox_Dark_Hard}ComboBox.background = @ijTextBackgroundL3
{Gruvbox_Dark_Hard}ComboBox.buttonBackground = @ijTextBackgroundL3 {Gruvbox_Dark_Hard}ComboBox.buttonBackground = $ComboBox.background
{Gruvbox_Dark_Hard}TextField.background = @ijTextBackgroundL3 {Gruvbox_Dark_Hard}TextField.background = @ijTextBackgroundL3
{Hiberbee_Dark}*.disabledForeground = #7F7E7D {Hiberbee_Dark}@disabledForeground = $ColorPalette.light3
{Hiberbee_Dark}*.disabledText = #7F7E7D {Hiberbee_Dark}*.disabledText = @disabledForeground
{Hiberbee_Dark}*.inactiveForeground = #7F7E7D {Hiberbee_Dark}*.disabledForeground = @disabledForeground
{Hiberbee_Dark}ProgressBar.background = lazy(Separator.foreground) {Hiberbee_Dark}*.inactiveForeground = @disabledForeground
{Hiberbee_Dark}Slider.trackColor = lazy(Separator.foreground) {Hiberbee_Dark}List.selectionInactiveBackground = $Table.selectionInactiveBackground
{Hiberbee_Dark}TabbedPane.focusColor = #5A5A5A {Hiberbee_Dark}ProgressBar.background = $Separator.foreground
{Hiberbee_Dark}TabbedPane.selectedBackground = #434241 {Hiberbee_Dark}RadioButtonMenuItem.selectionForeground = $MenuItem.selectionForeground
{Hiberbee_Dark}TabbedPane.selectedForeground = #70D7FF {Hiberbee_Dark}Slider.trackColor = $ColorPalette.light1
{Hiberbee_Dark}ToggleButton.selectedBackground = $ToggleButton.selectedBackground {Hiberbee_Dark}Slider.trackColor = $ColorPalette.dark10
{Hiberbee_Dark}ToggleButton.toolbar.selectedBackground = $ToggleButton.toolbar.selectedBackground {Hiberbee_Dark}Slider.thumbColor = @accentBaseColor
{Hiberbee_Dark}Table.selectionInactiveBackground = lazy(List.selectionInactiveBackground) {Hiberbee_Dark}ToggleButton.foreground = $Button.foreground
{Hiberbee_Dark}Tree.selectionBackground = lazy(List.selectionBackground) {Hiberbee_Dark}ToolBar.background = @background
{Hiberbee_Dark}Tree.selectionInactiveBackground = lazy(List.selectionInactiveBackground)
{High_Contrast}Component.accentColor = lazy(Component.focusColor) {High_Contrast}@accentBaseColor = $TabbedPane.underlineColor
{High_Contrast}Button.hoverBorderColor = #1AEBFF {High_Contrast}Slider.thumbBorderColor = $Slider.thumbColor
{High_Contrast}HelpButton.hoverBorderColor = #1AEBFF {High_Contrast}Slider.focusedThumbBorderColor = @background
{High_Contrast}ToggleButton.selectedBackground = #fff {High_Contrast}Slider.focusedColor = $Component.focusColor
{High_Contrast}ToggleButton.selectedForeground = #000 {High_Contrast}Slider.focusWidth = 2
{High_Contrast}ToggleButton.disabledSelectedBackground = #444 {High_Contrast}ToggleButton.selectedBackground = @selectionBackground
{High_Contrast}ToggleButton.toolbar.selectedBackground = #3333FF {High_Contrast}ToggleButton.selectedForeground = @selectionForeground
{High_Contrast}ToggleButton.disabledSelectedBackground = shade(@selectionBackground,50%)
{High_Contrast}ToggleButton.toolbar.selectedBackground = @selectionBackground
{High_Contrast}[style]Button.inTextField = \ {High_Contrast}[style]Button.inTextField = \
toolbar.hoverBackground: #444; \ toolbar.hoverBackground: #444; \
toolbar.pressedBackground: #666; \ toolbar.pressedBackground: #666; \
toolbar.selectedBackground: #fff toolbar.selectedBackground: @selectionBackground
{High_Contrast}[style]ToggleButton.inTextField = ${High_Contrast}[style]Button.inTextField
{Light_Flat}*.disabledForeground = #8C8C8C {Light_Flat}@accentBaseColor = $TabbedPane.underlineColor
{Light_Flat}*.inactiveForeground = #8C8C8C {Light_Flat}@accentFocusColor = lighten(@accentBaseColor,15%)
{Light_Flat}@disabledForeground = #808080
{Light_Flat}*.disabledText = @disabledForeground
{Light_Flat}*.disabledForeground = @disabledForeground
{Light_Flat}*.inactiveForeground = @disabledForeground
{Light_Flat}CheckBox.icon[filled].background = #fff {Light_Flat}CheckBox.icon[filled].background = #fff
{Light_Flat}CheckBox.icon[filled].checkmarkColor = #fff {Light_Flat}CheckBox.icon[filled].checkmarkColor = #fff
{Light_Flat}Component.accentColor = lazy(TabbedPane.underlineColor) {Light_Flat}ComboBox.background = $ComboBox.editableBackground
{Light_Flat}ComboBox.background = lazy(ComboBox.editableBackground) {Light_Flat}ComboBox.buttonBackground = $ComboBox.background
{Light_Flat}ComboBox.buttonBackground = lazy(ComboBox.editableBackground) {Light_Flat}ProgressBar.selectionForeground = @foreground
{Light_Flat}Separator.foreground = lazy(ToolBar.separatorColor) {Light_Flat}Separator.foreground = @ijSeparatorLight
{Light_Flat}TableHeader.background = #E5E5E9 {Light_Flat}TableHeader.background = #E5E5E9
{Light_Flat}TextPane.foreground = lazy(TextField.foreground) {Light_Flat}TextPane.foreground = $TextField.foreground
{Light_Flat}CheckBoxMenuItem.selectionForeground = lazy(MenuItem.selectionForeground) {Light_Flat}ToggleButton.foreground = $Button.foreground
{Light_Flat}RadioButtonMenuItem.selectionForeground = lazy(MenuItem.selectionForeground) {Light_Flat}CheckBoxMenuItem.selectionForeground = $MenuItem.selectionForeground
{Light_Flat}RadioButtonMenuItem.selectionForeground = $MenuItem.selectionForeground
{Monocai}Button.default.foreground = #2D2A2F {Monocai}@accentUnderlineColor = @accentBaseColor
{Monocai}*.acceleratorForeground = @menuAcceleratorForeground
{Monocai}*.acceleratorSelectionForeground = @menuAcceleratorSelectionForeground
{Monocai}Button.default.foreground = @background
{Monocai}MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {Monocai}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
{Monocai}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {Monocai}TabbedPane.underlineColor = @accentUnderlineColor
@Monocai.acceleratorForeground = lazy(MenuItem.disabledForeground)
@Monocai.acceleratorSelectionForeground = lighten(MenuItem.disabledForeground,10%,lazy)
{Monocai}CheckBoxMenuItem.acceleratorForeground = @Monocai.acceleratorForeground
{Monocai}CheckBoxMenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
{Monocai}Menu.acceleratorForeground = @Monocai.acceleratorForeground
{Monocai}Menu.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
{Monocai}MenuItem.acceleratorForeground = @Monocai.acceleratorForeground
{Monocai}MenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
{Monocai}RadioButtonMenuItem.acceleratorForeground = @Monocai.acceleratorForeground
{Monocai}RadioButtonMenuItem.acceleratorSelectionForeground = @Monocai.acceleratorSelectionForeground
{Monocai}TextField.background = @ijTextBackgroundL4 {Monocai}TextField.background = @ijTextBackgroundL4
@Monocai.selectionBackground = lazy(TextField.selectionBackground) @Monocai.selectionBackground = $TextField.selectionBackground
{Monocai}ComboBox.selectionBackground = @Monocai.selectionBackground {Monocai}ComboBox.selectionBackground = @Monocai.selectionBackground
{Monocai}List.selectionBackground = @Monocai.selectionBackground {Monocai}List.selectionBackground = @Monocai.selectionBackground
{Monocai}Table.selectionBackground = @Monocai.selectionBackground {Monocai}Table.selectionBackground = @Monocai.selectionBackground
{Monocai}Tree.selectionBackground = @Monocai.selectionBackground {Monocai}Tree.selectionBackground = @Monocai.selectionBackground
@Monocai.selectionInactiveBackground = lazy(MenuItem.selectionBackground) @Monocai.selectionInactiveBackground = $MenuItem.selectionBackground
{Monocai}List.selectionInactiveBackground = @Monocai.selectionInactiveBackground {Monocai}List.selectionInactiveBackground = @Monocai.selectionInactiveBackground
{Monocai}Table.selectionInactiveBackground = @Monocai.selectionInactiveBackground {Monocai}Table.selectionInactiveBackground = @Monocai.selectionInactiveBackground
{Monocai}Tree.selectionInactiveBackground = @Monocai.selectionInactiveBackground {Monocai}Tree.selectionInactiveBackground = @Monocai.selectionInactiveBackground
{Monokai_Pro---Subtheme}Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Monokai_Pro---Subtheme}@disabledForeground = shade(@foreground,40%)
{Monokai_Pro---Subtheme}Tree.selectionBackground = lazy(List.selectionBackground) {Monokai_Pro---Subtheme}*.disabledText = @disabledForeground
{Monokai_Pro---Subtheme}Separator.foreground = lazy(Slider.trackColor) {Monokai_Pro---Subtheme}*.disabledForeground = @disabledForeground
{Monokai_Pro---Subtheme}ToolBar.separatorColor = lazy(Slider.trackColor) {Monokai_Pro---Subtheme}*.inactiveForeground = @disabledForeground
{Monokai_Pro---Subtheme}ProgressBar.selectionBackground = #fff
{Monokai_Pro---Subtheme}Table.selectionInactiveForeground = $List.selectionInactiveForeground
{Monokai_Pro---Subtheme}Tree.selectionBackground = $List.selectionBackground
{Monokai_Pro---Subtheme}ToggleButton.foreground = $Button.foreground
{Monokai_Pro---Subtheme}Separator.foreground = @ijSeparatorDark
{Monokai_Pro---Subtheme}ToolBar.separatorColor = $Separator.foreground
{Monokai_Pro---Subtheme}ToolBar.background = @background
{Nord}*.inactiveForeground = #616E88 {Nord}@disabledForeground = #616E88
{Nord}*.disabledText = @disabledForeground
{Nord}*.disabledForeground = @disabledForeground
{Nord}*.inactiveForeground = @disabledForeground
{Nord}MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {Nord}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
{Nord}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {Nord}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
{Nord}List.selectionBackground = lazy(Tree.selectionBackground) {Nord}RadioButtonMenuItem.selectionBackground = $MenuItem.selectionBackground
{Nord}List.selectionForeground = lazy(Tree.selectionForeground) {Nord}ProgressBar.selectionBackground = @foreground
{Nord}Table.selectionBackground = lazy(Tree.selectionBackground) {Nord}ProgressBar.selectionForeground = @background
{Nord}Table.selectionForeground = lazy(Tree.selectionForeground) {Nord}List.selectionBackground = $Tree.selectionBackground
{Nord}TextField.selectionBackground = lazy(Tree.selectionBackground) {Nord}List.selectionForeground = $Tree.selectionForeground
{Nord}TextField.selectionForeground = lazy(Tree.selectionForeground) {Nord}Table.selectionBackground = $Tree.selectionBackground
{Nord}Tree.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Nord}Table.selectionForeground = $Tree.selectionForeground
{Nord}TextField.selectionBackground = $Tree.selectionBackground
{Nord}TextField.selectionForeground = $Tree.selectionForeground
{Nord}Tree.selectionInactiveForeground = $List.selectionInactiveForeground
{NotReallyMDTheme}*.selectionInactiveBackground = #21384E {NotReallyMDTheme}*.selectionInactiveBackground = #21384E
{NotReallyMDTheme}ToolBar.separatorColor = lazy(Separator.foreground) {NotReallyMDTheme}ToolBar.separatorColor = $Separator.foreground
{One_Dark}List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground)
{One_Dark}MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {One_Dark}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
{One_Dark}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {One_Dark}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
{One_Dark}ProgressBar.background = lazy(Separator.foreground) {One_Dark}ProgressBar.background = $Separator.foreground
{One_Dark}Slider.trackColor = lazy(Separator.foreground) {One_Dark}ProgressBar.selectionForeground = #fff
{One_Dark}Slider.focusedColor = fade(#568af2,40%) {One_Dark}Table.background = $Tree.background
{One_Dark}Table.background = lazy(Tree.background) {One_Dark}Table.selectionBackground = $Tree.selectionBackground
{One_Dark}Table.selectionBackground = lazy(Tree.selectionBackground) {One_Dark}TextField.selectionBackground = $List.selectionBackground
{One_Dark}TextField.selectionBackground = lazy(List.selectionBackground) {One_Dark}Tree.selectionForeground = $List.selectionForeground
{One_Dark}Tree.selectionForeground = lazy(List.selectionForeground)
{Solarized_Dark---4lex4}*.inactiveForeground = #657B83 {Solarized_Dark---4lex4}@accentBaseColor = $TabbedPane.underlineColor
{Solarized_Dark---4lex4}Component.accentColor = lazy(TabbedPane.underlineColor) {Solarized_Dark---4lex4}*.acceleratorForeground = @menuAcceleratorForeground
{Solarized_Dark---4lex4}ComboBox.background = lazy(ComboBox.editableBackground) {Solarized_Dark---4lex4}ComboBox.background = $ComboBox.editableBackground
{Solarized_Dark---4lex4}ComboBox.buttonBackground = lazy(ComboBox.editableBackground) {Solarized_Dark---4lex4}ComboBox.buttonBackground = $ComboBox.editableBackground
{Solarized_Dark---4lex4}Slider.focusedColor = fade($Component.focusColor,80%,derived) {Solarized_Dark---4lex4}Slider.disabledTrackColor = $ColorPalette.colorSeparator
{Solarized_Dark---4lex4}ToolBar.separatorColor = lazy(Separator.foreground)
{Solarized_Light---4lex4}*.inactiveForeground = #839496 {Solarized_Light---4lex4}@accentBaseColor = $TabbedPane.underlineColor
{Solarized_Light---4lex4}Button.default.hoverBackground = darken($Button.default.background,3%,derived) {Solarized_Light---4lex4}Slider.thumbColor = $ProgressBar.foreground
{Solarized_Light---4lex4}Component.accentColor = lazy(TabbedPane.underlineColor) {Solarized_Light---4lex4}Slider.disabledTrackColor = $ColorPalette.colorSeparator
{Spacegray}ComboBox.background = @ijTextBackgroundL4 {Spacegray}ComboBox.background = @ijTextBackgroundL4
{Spacegray}ComboBox.buttonBackground = @ijTextBackgroundL4 {Spacegray}ComboBox.buttonBackground = $ComboBox.background
{Spacegray}TextField.background = @ijTextBackgroundL4 {Spacegray}TextField.background = @ijTextBackgroundL4
{Spacegray}TextField.selectionBackground = lazy(Tree.selectionBackground)
{Spacegray}TextField.selectionForeground = lazy(Tree.selectionForeground)
{vuesion-theme}*.disabledForeground = #8C8C8C {vuesion-theme}@accentBaseColor = $TabbedPane.underlineColor
{vuesion-theme}*.disabledText = #8C8C8C {vuesion-theme}@disabledForeground = #8C8C8C
{vuesion-theme}*.inactiveForeground = #8C8C8C {vuesion-theme}*.disabledText = @disabledForeground
{vuesion-theme}Component.accentColor = lazy(Button.default.endBackground) {vuesion-theme}*.disabledForeground = @disabledForeground
{vuesion-theme}*.inactiveForeground = @disabledForeground
{vuesion-theme}MenuItem.checkBackground = @ijMenuCheckBackgroundL10 {vuesion-theme}MenuItem.checkBackground = @ijMenuCheckBackgroundL10
{vuesion-theme}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10 {vuesion-theme}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL10
{vuesion-theme}Slider.trackValueColor = #ececee {vuesion-theme}ProgressBar.background = #303a45
{vuesion-theme}Slider.trackColor = #303a45 {vuesion-theme}ProgressBar.foreground = #ececee
{vuesion-theme}Slider.thumbColor = #ececee {vuesion-theme}Slider.thumbColor = #ececee
{vuesion-theme}Slider.focusedColor = fade(#ececee,20%) {vuesion-theme}Slider.focusedColor = fade($Slider.thumbColor,20%)
{vuesion-theme}ComboBox.background = @ijTextBackgroundL4 {vuesion-theme}ComboBox.background = @ijTextBackgroundL4
{vuesion-theme}ComboBox.buttonBackground = @ijTextBackgroundL4 {vuesion-theme}ComboBox.buttonBackground = $ComboBox.background
{vuesion-theme}TextField.background = @ijTextBackgroundL4 {vuesion-theme}TextField.background = @ijTextBackgroundL4
{vuesion-theme}TextField.selectionBackground = lighten(#303A45,15%) {vuesion-theme}TextField.selectionBackground = lighten(#303A45,15%)
{Xcode-Dark}@accentBaseColor = $List.selectionBackground
{Xcode-Dark}TextField.background = @ijTextBackgroundL4 {Xcode-Dark}TextField.background = @ijTextBackgroundL4
# Material Theme UI Lite # Material Theme UI Lite
[light]{author-Mallowigi}MenuItem.checkBackground = @ijMenuCheckBackgroundD10 {author-Mallowigi}[light]controlHighlight = lighten($controlShadow,8%)
[light]{author-Mallowigi}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundD10 {author-Mallowigi}[light]controlLtHighlight = lighten($controlShadow,15%)
[dark]{author-Mallowigi}MenuItem.checkBackground = @ijMenuCheckBackgroundL20 {author-Mallowigi}[light]controlDkShadow = darken($controlShadow,15%)
[dark]{author-Mallowigi}MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20 {author-Mallowigi}[dark]controlHighlight = darken($controlShadow,10%)
{author-Mallowigi}[dark]controlLtHighlight = darken($controlShadow,15%)
{author-Mallowigi}[dark]controlDkShadow = lighten($controlShadow,10%)
{author-Mallowigi}Tree.selectionInactiveBackground = lazy(List.selectionInactiveBackground) {author-Mallowigi}Button.hoverBorderColor = $Button.focusedBorderColor
{author-Mallowigi}HelpButton.hoverBorderColor = $Button.focusedBorderColor
{Arc_Dark}ComboBox.selectionBackground = lazy(List.selectionBackground) {author-Mallowigi}[light]ToggleButton.selectedForeground = #000
{Arc_Dark}Table.selectionBackground = lazy(List.selectionBackground) {author-Mallowigi}[dark]ToggleButton.selectedForeground = #fff
{Atom_One_Dark}Separator.foreground = lazy(Slider.trackColor) {author-Mallowigi}[light]MenuItem.checkBackground = @ijMenuCheckBackgroundD10
{Atom_One_Dark}ToolBar.separatorColor = lazy(Slider.trackColor) {author-Mallowigi}[light]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundD10
{author-Mallowigi}[dark]MenuItem.checkBackground = @ijMenuCheckBackgroundL20
{author-Mallowigi}[dark]MenuItem.underlineSelectionCheckBackground = @ijMenuCheckBackgroundL20
{Atom_One_Light}List.selectionBackground = lazy(Table.selectionBackground) {author-Mallowigi}[light]Separator.foreground = @ijSeparatorLight
{Atom_One_Light}Tree.selectionBackground = lazy(Table.selectionBackground) {author-Mallowigi}[dark]Separator.foreground = @ijSeparatorDark
{Atom_One_Light}TabbedPane.contentAreaColor = lazy(Separator.foreground) {author-Mallowigi}ProgressBar.selectionBackground = @foreground
{author-Mallowigi}TabbedPane.selectedBackground = mix(@background,$ColorPalette.table,60%)
{author-Mallowigi}ToolBar.separatorColor = $Separator.foreground
{author-Mallowigi}Button.foreground = @foreground
{author-Mallowigi}Tree.foreground = @foreground
{Arc_Dark}ComboBox.selectionBackground = $List.selectionBackground
{Arc_Dark}ProgressBar.selectionBackground = #fff
{Arc_Dark}ProgressBar.selectionForeground = #fff
{Arc_Dark}Table.selectionBackground = $List.selectionBackground
{Arc_Dark}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Atom_One_Dark}ProgressBar.selectionBackground = #fff
{Atom_One_Dark}ProgressBar.selectionForeground = #fff
{Atom_One_Dark}List.selectionBackground = $Table.selectionBackground
{Atom_One_Dark}Tree.selectionBackground = $Table.selectionBackground
{Atom_One_Dark}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Atom_One_Dark}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Atom_One_Light}@disabledForeground = shade($ColorPalette.dis,20%)
{Atom_One_Light}*.disabledText = @disabledForeground
{Atom_One_Light}*.disabledForeground = @disabledForeground
{Atom_One_Light}*.inactiveForeground = @disabledForeground
{Atom_One_Light}TabbedPane.contentAreaColor = $Separator.foreground
{Dracula---Mallowigi}*.selectionBackground = #44475A
{Dracula---Mallowigi}List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground)
{Dracula---Mallowigi}ProgressBar.selectionBackground = #fff {Dracula---Mallowigi}ProgressBar.selectionBackground = #fff
{Dracula---Mallowigi}ProgressBar.selectionForeground = #fff {Dracula---Mallowigi}ProgressBar.selectionForeground = #fff
{Dracula---Mallowigi}RadioButtonMenuItem.selectionForeground = lazy(CheckBoxMenuItem.selectionForeground) {Dracula---Mallowigi}List.selectionBackground = $Table.selectionBackground
{Dracula---Mallowigi}Table.selectionForeground = lazy(List.selectionForeground) {Dracula---Mallowigi}Tree.selectionBackground = $Table.selectionBackground
{Dracula---Mallowigi}Separator.foreground = lazy(Slider.trackColor) {Dracula---Mallowigi}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Dracula---Mallowigi}ToolBar.separatorColor = lazy(Slider.trackColor) {Dracula---Mallowigi}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
{GitHub}ProgressBar.selectionBackground = #222 {GitHub}ProgressBar.selectionBackground = #222
{GitHub}ProgressBar.selectionForeground = #222 {GitHub}ProgressBar.selectionForeground = #222
{GitHub}TextField.background = @ijTextBackgroundL3 {GitHub}TextField.background = @ijTextBackgroundL3
{GitHub}List.selectionBackground = lazy(Table.selectionBackground) {GitHub}List.selectionBackground = $Table.selectionBackground
{GitHub}Tree.selectionBackground = lazy(Table.selectionBackground) {GitHub}Tree.selectionBackground = $Table.selectionBackground
{GitHub}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{GitHub}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
{GitHub_Dark}ComboBox.selectionBackground = lazy(Tree.selectionBackground) {GitHub_Dark}ComboBox.selectionBackground = $Tree.selectionBackground
{GitHub_Dark}Table.selectionBackground = lazy(Tree.selectionBackground) {GitHub_Dark}ProgressBar.selectionForeground = #fff
{GitHub_Dark}Separator.foreground = lazy(Slider.trackColor) {GitHub_Dark}Slider.trackColor = lighten(#2b3036,5%)
{GitHub_Dark}ToolBar.separatorColor = lazy(Slider.trackColor) {GitHub_Dark}Table.selectionBackground = $Tree.selectionBackground
{GitHub_Dark}Tree.selectionInactiveBackground = $Table.selectionInactiveBackground
{Light_Owl}CheckBoxMenuItem.selectionForeground = lazy(CheckBoxMenuItem.foreground) {Light_Owl}@disabledForeground = shade($ColorPalette.dis,10%)
{Light_Owl}ComboBox.selectionForeground = lazy(ComboBox.foreground) {Light_Owl}*.disabledText = @disabledForeground
{Light_Owl}List.selectionInactiveForeground = lazy(List.foreground) {Light_Owl}*.disabledForeground = @disabledForeground
{Light_Owl}Menu.selectionForeground = lazy(Menu.foreground) {Light_Owl}*.inactiveForeground = @disabledForeground
{Light_Owl}MenuBar.selectionForeground = lazy(MenuBar.foreground) {Light_Owl}CheckBoxMenuItem.selectionForeground = $CheckBoxMenuItem.foreground
{Light_Owl}MenuItem.selectionForeground = lazy(MenuItem.foreground) {Light_Owl}ComboBox.selectionForeground = $ComboBox.foreground
{Light_Owl}ProgressBar.selectionBackground = #111 {Light_Owl}List.selectionInactiveForeground = $Table.selectionInactiveForeground
{Light_Owl}ProgressBar.selectionForeground = #fff {Light_Owl}Menu.selectionForeground = $Menu.foreground
{Light_Owl}Spinner.selectionForeground = lazy(Spinner.foreground) {Light_Owl}MenuBar.selectionForeground = $MenuBar.foreground
{Light_Owl}Table.selectionForeground = lazy(Table.foreground) {Light_Owl}MenuItem.selectionForeground = $MenuItem.foreground
{Light_Owl}TextField.selectionForeground = lazy(TextField.foreground) {Light_Owl}Table.selectionForeground = $List.selectionForeground
{Light_Owl}TextField.selectionForeground = $TextField.foreground
{Light_Owl}TextField.background = @ijTextBackgroundL3 {Light_Owl}TextField.background = @ijTextBackgroundL3
{Light_Owl}List.selectionBackground = lazy(Table.selectionBackground) {Light_Owl}List.selectionBackground = $Table.selectionBackground
{Light_Owl}Tree.selectionBackground = lazy(Table.selectionBackground) {Light_Owl}Tree.selectionBackground = $Table.selectionBackground
{Light_Owl}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Light_Owl}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Material_Darker}*.selectionBackground = lighten(#2D2D2D,15%) {Material_Darker}@disabledForeground = tint($ColorPalette.dis,30%)
{Material_Darker}Separator.foreground = lazy(Slider.trackColor) {Material_Darker}*.disabledText = @disabledForeground
{Material_Darker}ToolBar.separatorColor = lazy(Slider.trackColor) {Material_Darker}*.disabledForeground = @disabledForeground
{Material_Darker}*.inactiveForeground = @disabledForeground
{Material_Darker}*.selectionBackground = lighten($ColorPalette.tree,15%)
{Material_Darker}ProgressBar.selectionForeground = #fff
{Material_Darker}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Material_Deep_Ocean}*.selectionBackground = lighten(#222533,15%) {Material_Deep_Ocean}@disabledForeground = tint($ColorPalette.dis,10%)
{Material_Deep_Ocean}Separator.foreground = lazy(Slider.trackColor) {Material_Deep_Ocean}*.disabledText = @disabledForeground
{Material_Deep_Ocean}ToolBar.separatorColor = lazy(Slider.trackColor) {Material_Deep_Ocean}*.disabledForeground = @disabledForeground
{Material_Deep_Ocean}*.inactiveForeground = @disabledForeground
{Material_Deep_Ocean}*.selectionBackground = lighten($ColorPalette.tree,15%)
{Material_Deep_Ocean}ProgressBar.selectionBackground = #fff
{Material_Deep_Ocean}Slider.trackColor = lighten(#1A1C25,5%)
{Material_Deep_Ocean}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Material_Lighter}List.selectionInactiveForeground = lazy(Tree.selectionInactiveForeground) {Material_Lighter}@disabledForeground = shade($ColorPalette.dis,30%)
{Material_Lighter}*.disabledText = @disabledForeground
{Material_Lighter}*.disabledForeground = @disabledForeground
{Material_Lighter}*.inactiveForeground = @disabledForeground
{Material_Lighter}ComboBox.selectionBackground = $List.selectionBackground
{Material_Lighter}List.selectionForeground = $Table.selectionForeground
{Material_Lighter}List.selectionInactiveForeground = $Table.selectionInactiveForeground
{Material_Lighter}ProgressBar.selectionBackground = #222 {Material_Lighter}ProgressBar.selectionBackground = #222
{Material_Lighter}ProgressBar.selectionForeground = #fff {Material_Lighter}RadioButtonMenuItem.selectionForeground = $Table.selectionForeground
{Material_Lighter}ComboBox.selectionBackground = lazy(List.selectionBackground) {Material_Lighter}Table.selectionBackground = $List.selectionBackground
{Material_Lighter}Table.selectionBackground = lazy(List.selectionBackground) {Material_Lighter}Tree.selectionForeground = $Table.selectionForeground
{Material_Lighter}List.selectionForeground = lazy(Table.selectionForeground) {Material_Lighter}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Material_Lighter}RadioButtonMenuItem.selectionForeground = lazy(Table.selectionForeground)
{Material_Lighter}Tree.selectionForeground = lazy(Table.selectionForeground)
{Material_Oceanic}@disabledForeground = tint($ColorPalette.dis,30%)
{Material_Oceanic}*.disabledText = @disabledForeground
{Material_Oceanic}*.disabledForeground = @disabledForeground
{Material_Oceanic}*.inactiveForeground = @disabledForeground
{Material_Oceanic}ProgressBar.selectionBackground = #ddd {Material_Oceanic}ProgressBar.selectionBackground = #ddd
{Material_Oceanic}ProgressBar.selectionForeground = #ddd {Material_Oceanic}ProgressBar.selectionForeground = #ddd
{Material_Oceanic}Separator.foreground = lazy(Slider.trackColor) {Material_Oceanic}List.selectionBackground = $Table.selectionBackground
{Material_Oceanic}ToolBar.separatorColor = lazy(Slider.trackColor) {Material_Oceanic}Tree.selectionBackground = $Table.selectionBackground
{Material_Oceanic}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Material_Oceanic}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Material_Palenight}@disabledForeground = tint($ColorPalette.dis,20%)
{Material_Palenight}*.disabledText = @disabledForeground
{Material_Palenight}*.disabledForeground = @disabledForeground
{Material_Palenight}*.inactiveForeground = @disabledForeground
{Material_Palenight}ProgressBar.selectionBackground = #ddd {Material_Palenight}ProgressBar.selectionBackground = #ddd
{Material_Palenight}ProgressBar.selectionForeground = #ddd {Material_Palenight}ProgressBar.selectionForeground = #ddd
{Material_Palenight}List.selectionBackground = lazy(Table.selectionBackground) {Material_Palenight}List.selectionBackground = $Table.selectionBackground
{Material_Palenight}Tree.selectionBackground = lazy(Table.selectionBackground) {Material_Palenight}Tree.selectionBackground = $Table.selectionBackground
{Material_Palenight}Separator.foreground = lazy(Slider.trackColor) {Material_Palenight}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Material_Palenight}ToolBar.separatorColor = lazy(Slider.trackColor) {Material_Palenight}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Monokai_Pro---Mallowigi}List.selectionForeground = lazy(Table.selectionForeground) {Monokai_Pro---Mallowigi}@disabledForeground = tint($ColorPalette.dis,20%)
{Monokai_Pro---Mallowigi}RadioButtonMenuItem.selectionForeground = lazy(Table.selectionForeground) {Monokai_Pro---Mallowigi}*.disabledText = @disabledForeground
{Monokai_Pro---Mallowigi}Table.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Monokai_Pro---Mallowigi}*.disabledForeground = @disabledForeground
{Monokai_Pro---Mallowigi}Tree.selectionForeground = lazy(Table.selectionForeground) {Monokai_Pro---Mallowigi}*.inactiveForeground = @disabledForeground
{Monokai_Pro---Mallowigi}Tree.selectionInactiveForeground = lazy(List.selectionInactiveForeground) {Monokai_Pro---Mallowigi}RadioButtonMenuItem.selectionForeground = $MenuItem.selectionForeground
{Monokai_Pro---Mallowigi}Separator.foreground = lazy(Slider.trackColor) {Monokai_Pro---Mallowigi}List.selectionForeground = $Table.selectionForeground
{Monokai_Pro---Mallowigi}ToolBar.separatorColor = lazy(Slider.trackColor) {Monokai_Pro---Mallowigi}Tree.selectionForeground = $Table.selectionForeground
{Monokai_Pro---Mallowigi}List.selectionInactiveForeground = $Table.selectionInactiveForeground
{Monokai_Pro---Mallowigi}List.selectionBackground = $Table.selectionBackground
{Monokai_Pro---Mallowigi}Tree.selectionBackground = $Table.selectionBackground
{Monokai_Pro---Mallowigi}List.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Monokai_Pro---Mallowigi}Table.selectionInactiveBackground = $Tree.selectionInactiveBackground
{Moonlight}ComboBox.selectionBackground = lazy(List.selectionBackground) {Moonlight}ComboBox.selectionBackground = $List.selectionBackground
{Moonlight}Table.selectionBackground = lazy(List.selectionBackground) {Moonlight}ProgressBar.selectionForeground = #000
{Moonlight}Separator.foreground = lazy(Slider.trackColor) {Moonlight}Table.selectionBackground = $List.selectionBackground
{Moonlight}ToolBar.separatorColor = lazy(Slider.trackColor) {Moonlight}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Night_Owl}ProgressBar.selectionBackground = #ddd
{Night_Owl}ProgressBar.selectionForeground = #ddd
{Solarized_Dark---Mallowigi}@disabledForeground = tint($ColorPalette.dis,20%)
{Solarized_Dark---Mallowigi}*.disabledForeground = @disabledForeground
{Solarized_Dark---Mallowigi}*.inactiveForeground = @disabledForeground
{Solarized_Dark---Mallowigi}*.disabledText = @disabledForeground
{Solarized_Dark---Mallowigi}ProgressBar.selectionBackground = #ccc {Solarized_Dark---Mallowigi}ProgressBar.selectionBackground = #ccc
{Solarized_Dark---Mallowigi}ProgressBar.selectionForeground = #ccc {Solarized_Dark---Mallowigi}ProgressBar.selectionForeground = #ccc
{Solarized_Dark---Mallowigi}Separator.foreground = lazy(Slider.trackColor) {Solarized_Dark---Mallowigi}Slider.trackColor = lighten(@background,10%)
{Solarized_Dark---Mallowigi}ToolBar.separatorColor = lazy(Slider.trackColor) {Solarized_Dark---Mallowigi}Table.selectionBackground = $List.selectionBackground
{Solarized_Dark---Mallowigi}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Solarized_Light---Mallowigi}@disabledForeground = tint(@foreground,30%)
{Solarized_Light---Mallowigi}*.disabledForeground = @disabledForeground
{Solarized_Light---Mallowigi}*.inactiveForeground = @disabledForeground
{Solarized_Light---Mallowigi}*.disabledText = @disabledForeground
{Solarized_Light---Mallowigi}ProgressBar.selectionBackground = #222 {Solarized_Light---Mallowigi}ProgressBar.selectionBackground = #222
{Solarized_Light---Mallowigi}ProgressBar.selectionForeground = #fff {Solarized_Light---Mallowigi}ComboBox.selectionBackground = $List.selectionBackground
{Solarized_Light---Mallowigi}ComboBox.selectionBackground = lazy(List.selectionBackground) {Solarized_Light---Mallowigi}Slider.disabledTrackColor = lighten($Slider.trackColor,5%)
{Solarized_Light---Mallowigi}Table.selectionBackground = lazy(List.selectionBackground) {Solarized_Light---Mallowigi}Table.selectionBackground = $List.selectionBackground
{Solarized_Light---Mallowigi}Separator.foreground = lazy(Slider.trackColor) {Solarized_Light---Mallowigi}Tree.selectionInactiveBackground = $List.selectionInactiveBackground
{Solarized_Light---Mallowigi}ToolBar.separatorColor = lazy(Slider.trackColor) {Solarized_Light---Mallowigi}Button.toolbar.selectedBackground = darken($@background,15%)
{Solarized_Light---Mallowigi}ToggleButton.toolbar.selectedBackground = $Button.toolbar.selectedBackground

View File

@@ -52,6 +52,8 @@ public class DemoPrefs
} }
public static void setupLaf( String[] args ) { public static void setupLaf( String[] args ) {
// com.formdev.flatlaf.demo.intellijthemes.IJThemesDump.install();
// set look and feel // set look and feel
try { try {
if( args.length > 0 ) if( args.length > 0 )

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2025 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.demo.intellijthemes;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicReference;
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.IntelliJTheme;
import com.formdev.flatlaf.util.LoggingFacade;
/**
* @author Karl Tauber
*/
public class IJThemesDump
{
// same as UIDefaultsLoader.KEY_PROPERTIES
private static final String KEY_PROPERTIES = "FlatLaf.internal.properties";
public static void enablePropertiesRecording() {
System.setProperty( KEY_PROPERTIES, "true" );
}
public static void install() {
enablePropertiesRecording();
UIManager.addPropertyChangeListener( e -> {
if( "lookAndFeel".equals( e.getPropertyName() ) ) {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
if( lookAndFeel instanceof IntelliJTheme.ThemeLaf ) {
IntelliJTheme theme = (lookAndFeel.getClass() == IntelliJTheme.ThemeLaf.class)
? ((IntelliJTheme.ThemeLaf)lookAndFeel).getTheme()
: null;
String name = (theme != null) ? theme.name : lookAndFeel.getClass().getSimpleName();
File dir = new File( "dumps/properties" );
dumpProperties( dir, name, UIManager.getLookAndFeelDefaults() );
}
}
} );
}
public static void dumpProperties( File dir, String name, UIDefaults defaults ) {
String content = dumpPropertiesToString( defaults );
if( content == null )
return;
// write to file
File file = new File( dir, name + ".properties" );
file.getParentFile().mkdirs();
try( Writer fileWriter = new OutputStreamWriter(
new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
{
fileWriter.write( content );
} catch( IOException ex ) {
LoggingFacade.INSTANCE.logSevere( null, ex );
}
}
public static String dumpPropertiesToString( UIDefaults defaults ) {
Properties properties = (Properties) defaults.get( KEY_PROPERTIES );
if( properties == null )
return null;
// dump to string
StringWriter stringWriter = new StringWriter( 100000 );
PrintWriter out = new PrintWriter( stringWriter );
out.printf( "@baseTheme = %s%n", FlatLaf.isLafDark() ? "dark" : "light" );
AtomicReference<String> lastPrefix = new AtomicReference<>();
properties.entrySet().stream()
.sorted( (e1, e2) -> ((String)e1.getKey()).compareTo( (String) e2.getKey() ) )
.forEach( e -> {
String key = (String) e.getKey();
String value = (String) e.getValue();
String prefix = keyPrefix( key );
if( !prefix.equals( lastPrefix.get() ) ) {
lastPrefix.set( prefix );
out.printf( "%n%n#---- %s ----%n%n", prefix );
}
out.printf( "%-50s = %s%n", key, value.replace( ";", "; \\\n\t" ) );
} );
return stringWriter.toString().replace( "\r", "" );
}
private static String keyPrefix( String key ) {
int dotIndex = key.indexOf( '.' );
return (dotIndex > 0)
? key.substring( 0, dotIndex )
: key.endsWith( "UI" )
? key.substring( 0, key.length() - 2 )
: "";
}
}

View File

@@ -276,20 +276,21 @@ public class IJThemesPanel
return; return;
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
setTheme( themeInfo ); setTheme( themeInfo, false );
} ); } );
} }
private void setTheme( IJThemeInfo themeInfo ) { private void setTheme( IJThemeInfo themeInfo, boolean reload ) {
if( themeInfo == null ) if( themeInfo == null )
return; return;
// change look and feel // change look and feel
if( themeInfo.lafClassName != null ) { if( themeInfo.lafClassName != null ) {
if( themeInfo.lafClassName.equals( UIManager.getLookAndFeel().getClass().getName() ) ) if( !reload && themeInfo.lafClassName.equals( UIManager.getLookAndFeel().getClass().getName() ) )
return; return;
FlatAnimatedLafChange.showSnapshot(); if( !reload )
FlatAnimatedLafChange.showSnapshot();
try { try {
UIManager.setLookAndFeel( themeInfo.lafClassName ); UIManager.setLookAndFeel( themeInfo.lafClassName );
@@ -298,7 +299,8 @@ public class IJThemesPanel
showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex ); showInformationDialog( "Failed to create '" + themeInfo.lafClassName + "'.", ex );
} }
} else if( themeInfo.themeFile != null ) { } else if( themeInfo.themeFile != null ) {
FlatAnimatedLafChange.showSnapshot(); if( !reload )
FlatAnimatedLafChange.showSnapshot();
try { try {
if( themeInfo.themeFile.getName().endsWith( ".properties" ) ) if( themeInfo.themeFile.getName().endsWith( ".properties" ) )
@@ -320,7 +322,9 @@ public class IJThemesPanel
// update all components // update all components
FlatLaf.updateUI(); FlatLaf.updateUI();
FlatAnimatedLafChange.hideSnapshotWithAnimation();
if( !reload )
FlatAnimatedLafChange.hideSnapshotWithAnimation();
} }
private void browsePlugin() { private void browsePlugin() {
@@ -386,8 +390,8 @@ public class IJThemesPanel
// use invokeLater() because KEY_LAF_THEME_FILE is updated after this event // use invokeLater() because KEY_LAF_THEME_FILE is updated after this event
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
selectedCurrentLookAndFeel(); selectedCurrentLookAndFeel();
lastLafChangeTime = System.currentTimeMillis();
} ); } );
lastLafChangeTime = System.currentTimeMillis();
} }
} }
@@ -435,7 +439,7 @@ public class IJThemesPanel
} }
if( reload ) if( reload )
setTheme( themesList.getSelectedValue() ); setTheme( themesList.getSelectedValue(), true );
} }
} }
} }

View File

@@ -76,7 +76,7 @@
+ ProgressBar.foreground #c4c4c4 HSL 0 0 77 javax.swing.plaf.ColorUIResource [UI] + ProgressBar.foreground #c4c4c4 HSL 0 0 77 javax.swing.plaf.ColorUIResource [UI]
- ProgressBar.selectionForeground #eeeeee HSL 0 0 93 javax.swing.plaf.ColorUIResource [UI] - ProgressBar.selectionForeground #eeeeee HSL 0 0 93 javax.swing.plaf.ColorUIResource [UI]
+ ProgressBar.selectionForeground #3c3f41 HSL 204 4 25 javax.swing.plaf.ColorUIResource [UI] + ProgressBar.selectionForeground #1e2021 HSL 200 5 12 javax.swing.plaf.ColorUIResource [UI]
#---- RadioButton ---- #---- RadioButton ----
@@ -121,4 +121,4 @@
+ contrast ratio: ProgressBar.foreground #c4c4c4 #3c3f41 6.1 ! + contrast ratio: ProgressBar.foreground #c4c4c4 #3c3f41 6.1 !
- contrast ratio: ProgressBar.selectionForeground #eeeeee #4c87c8 3.2 !!!! - contrast ratio: ProgressBar.selectionForeground #eeeeee #4c87c8 3.2 !!!!
+ contrast ratio: ProgressBar.selectionForeground #3c3f41 #c4c4c4 6.1 ! + contrast ratio: ProgressBar.selectionForeground #1e2021 #c4c4c4 9.4

View File

@@ -60,6 +60,7 @@ import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.table.JTableHeader; import javax.swing.table.JTableHeader;
import com.formdev.flatlaf.*; import com.formdev.flatlaf.*;
import com.formdev.flatlaf.demo.intellijthemes.IJThemesDump;
import com.formdev.flatlaf.intellijthemes.FlatAllIJThemes; import com.formdev.flatlaf.intellijthemes.FlatAllIJThemes;
import com.formdev.flatlaf.testing.FlatTestLaf; import com.formdev.flatlaf.testing.FlatTestLaf;
import com.formdev.flatlaf.themes.*; import com.formdev.flatlaf.themes.*;
@@ -155,6 +156,8 @@ public class UIDefaultsDump
private static void dumpIntelliJThemes( File dir ) { private static void dumpIntelliJThemes( File dir ) {
dir = new File( dir, "intellijthemes" ); dir = new File( dir, "intellijthemes" );
IJThemesDump.enablePropertiesRecording();
for( LookAndFeelInfo info : FlatAllIJThemes.INFOS ) { for( LookAndFeelInfo info : FlatAllIJThemes.INFOS ) {
String lafClassName = info.getClassName(); String lafClassName = info.getClassName();
String relativeLafClassName = StringUtils.removeLeading( lafClassName, "com.formdev.flatlaf.intellijthemes." ); String relativeLafClassName = StringUtils.removeLeading( lafClassName, "com.formdev.flatlaf.intellijthemes." );
@@ -192,6 +195,15 @@ public class UIDefaultsDump
dump( dir, "_InputMap", lookAndFeel, defaults, key -> key.contains( "InputMap" ), false ); dump( dir, "_InputMap", lookAndFeel, defaults, key -> key.contains( "InputMap" ), false );
dumpActionMaps( dir, "_ActionMap", lookAndFeel, defaults ); dumpActionMaps( dir, "_ActionMap", lookAndFeel, defaults );
} }
if( lookAndFeel instanceof IntelliJTheme.ThemeLaf ) {
File cdir = new File( dir.getPath().replace( "intellijthemes", "intellijthemes-colors" ) );
dumpColorsToProperties( cdir, lookAndFeel, defaults );
// dump as .properties
File pdir = new File( dir.getPath().replace( "intellijthemes", "intellijthemes-properties" ) );
IJThemesDump.dumpProperties( pdir, lookAndFeel.getClass().getSimpleName(), defaults );
}
} }
private static void dump( File dir, String nameSuffix, private static void dump( File dir, String nameSuffix,
@@ -231,8 +243,8 @@ public class UIDefaultsDump
if( origFile != null ) { if( origFile != null ) {
try { try {
Map<String, String> defaults1 = parse( new InputStreamReader( Map<String, String> defaults1 = parse( new InputStreamReader(
new FileInputStream( origFile ), StandardCharsets.UTF_8 ) ); new FileInputStream( origFile ), StandardCharsets.UTF_8 ), false );
Map<String, String> defaults2 = parse( new StringReader( stringWriter.toString() ) ); Map<String, String> defaults2 = parse( new StringReader( stringWriter.toString() ), false );
content = diff( defaults1, defaults2 ); content = diff( defaults1, defaults2 );
} catch( Exception ex ) { } catch( Exception ex ) {
@@ -280,6 +292,45 @@ public class UIDefaultsDump
} }
} }
private static void dumpColorsToProperties( File dir, LookAndFeel lookAndFeel, UIDefaults defaults ) {
// dump to string
StringWriter stringWriter = new StringWriter( 100000 );
new UIDefaultsDump( lookAndFeel, defaults ).dumpColorsAsProperties( new PrintWriter( stringWriter ) );
String name = lookAndFeel instanceof MyBasicLookAndFeel
? BasicLookAndFeel.class.getSimpleName()
: lookAndFeel.getClass().getSimpleName();
File file = new File( dir, name + ".properties" );
// build and append differences
if( file.exists() ) {
try {
Map<String, String> defaults1 = parse( new InputStreamReader(
new FileInputStream( file ), StandardCharsets.UTF_8 ), true );
Map<String, String> defaults2 = parse( new StringReader( stringWriter.toString() ), true );
String diff = diff( defaults1, defaults2 );
if( !diff.isEmpty() ) {
stringWriter.write( "\n\n\n\n#==== Differences ==============================================================\n\n" );
stringWriter.write( diff );
}
} catch( Exception ex ) {
ex.printStackTrace();
return;
}
}
// write to file
file.getParentFile().mkdirs();
try( Writer fileWriter = new OutputStreamWriter(
new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
{
fileWriter.write( stringWriter.toString().replace( "\r", "" ) );
} catch( IOException ex ) {
ex.printStackTrace();
}
}
private static String diff( Map<String, String> defaults1, Map<String, String> defaults2 ) { private static String diff( Map<String, String> defaults1, Map<String, String> defaults2 ) {
TreeSet<String> keys = new TreeSet<>(); TreeSet<String> keys = new TreeSet<>();
keys.addAll( defaults1.keySet() ); keys.addAll( defaults1.keySet() );
@@ -355,7 +406,7 @@ public class UIDefaultsDump
buf.append( '\n' ); buf.append( '\n' );
} }
private static Map<String, String> parse( Reader in ) throws IOException { private static Map<String, String> parse( Reader in, boolean ignoreDiffs ) throws IOException {
Map<String, String> defaults = new LinkedHashMap<>(); Map<String, String> defaults = new LinkedHashMap<>();
try( BufferedReader reader = new BufferedReader( in ) ) { try( BufferedReader reader = new BufferedReader( in ) ) {
String lastKey = null; String lastKey = null;
@@ -371,6 +422,9 @@ public class UIDefaultsDump
continue; continue;
} }
if( ignoreDiffs && (trimmedLine.startsWith( "- " ) || trimmedLine.startsWith( "+ " )) )
continue;
if( Character.isWhitespace( line.charAt( 0 ) ) ) { if( Character.isWhitespace( line.charAt( 0 ) ) ) {
String value = defaults.get( lastKey ); String value = defaults.get( lastKey );
value += '\n' + line; value += '\n' + line;
@@ -443,6 +497,30 @@ public class UIDefaultsDump
dumpContrastRatios( out ); dumpContrastRatios( out );
} }
private void dumpColorsAsProperties( PrintWriter out ) {
defaults.keySet().stream()
.sorted( (key1, key2) -> {
return String.valueOf( key1 ).compareTo( String.valueOf( key2 ) );
} )
.forEach( key -> {
Color color = defaults.getColor( key );
if( color == null )
return;
String strKey = String.valueOf( key );
String prefix = keyPrefix( strKey );
if( !prefix.equals( lastPrefix ) ) {
lastPrefix = prefix;
out.printf( "%n%n#---- %s ----%n%n", prefix );
}
out.printf( "%-50s = #%06x", strKey, color.getRGB() & 0xffffff );
if( color.getAlpha() != 255 )
out.printf( "%02x", (color.getRGB() >> 24) & 0xff );
out.println();
} );
}
private void dumpActionMaps( PrintWriter out ) { private void dumpActionMaps( PrintWriter out ) {
dumpHeader( out ); dumpHeader( out );