UIDefaultsDump: dump contrast ratios

This commit is contained in:
Karl Tauber
2025-02-13 19:19:01 +01:00
parent 411a2f6d29
commit ed69049c08
8 changed files with 783 additions and 5 deletions

View File

@@ -38,6 +38,7 @@ import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
@@ -45,6 +46,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import javax.swing.*;
import javax.swing.UIDefaults.ActiveValue;
@@ -63,6 +65,7 @@ import com.formdev.flatlaf.testing.FlatTestLaf;
import com.formdev.flatlaf.themes.*;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.ColorFunctions.ColorFunction;
import com.jidesoft.plaf.LookAndFeelFactory;
import com.formdev.flatlaf.util.DerivedColor;
@@ -181,20 +184,20 @@ public class UIDefaultsDump
// the lazy color InternalFrame.closeHoverBackground is resolved)
defaults = (UIDefaults) defaults.clone();
dump( dir, "", lookAndFeel, defaults, key -> !key.contains( "InputMap" ) );
dump( dir, "", lookAndFeel, defaults, key -> !key.contains( "InputMap" ), true );
if( lookAndFeel.getClass() == FlatLightLaf.class || !(lookAndFeel instanceof FlatLaf) ) {
dump( dir, "_InputMap", lookAndFeel, defaults, key -> key.contains( "InputMap" ) );
dump( dir, "_InputMap", lookAndFeel, defaults, key -> key.contains( "InputMap" ), false );
dumpActionMaps( dir, "_ActionMap", lookAndFeel, defaults );
}
}
private static void dump( File dir, String nameSuffix,
LookAndFeel lookAndFeel, UIDefaults defaults, Predicate<String> keyFilter )
LookAndFeel lookAndFeel, UIDefaults defaults, Predicate<String> keyFilter, boolean contrastRatios )
{
// dump to string
StringWriter stringWriter = new StringWriter( 100000 );
new UIDefaultsDump( lookAndFeel, defaults ).dump( new PrintWriter( stringWriter ), keyFilter );
new UIDefaultsDump( lookAndFeel, defaults ).dump( new PrintWriter( stringWriter ), keyFilter, contrastRatios );
String name = lookAndFeel instanceof MyBasicLookAndFeel
? BasicLookAndFeel.class.getSimpleName()
@@ -354,12 +357,15 @@ public class UIDefaultsDump
Map<String, String> defaults = new LinkedHashMap<>();
try( BufferedReader reader = new BufferedReader( in ) ) {
String lastKey = null;
boolean inContrastRatios = false;
String line;
while( (line = reader.readLine()) != null ) {
String trimmedLine = line.trim();
if( trimmedLine.isEmpty() || trimmedLine.startsWith( "#" ) ) {
lastKey = null;
if( trimmedLine.contains( "#-------- Contrast Ratios --------" ) )
inContrastRatios = true;
continue;
}
@@ -374,6 +380,8 @@ public class UIDefaultsDump
String key = line.substring( 0, sep );
String value = line.substring( sep );
if( inContrastRatios )
key = "contrast ratio: " + key;
defaults.put( key, value );
lastKey = key;
@@ -403,7 +411,7 @@ public class UIDefaultsDump
out.printf( "OS %s%n", System.getProperty( "os.name" ) );
}
private void dump( PrintWriter out, Predicate<String> keyFilter ) {
private void dump( PrintWriter out, Predicate<String> keyFilter, boolean contrastRatios ) {
dumpHeader( out );
defaults.entrySet().stream()
@@ -428,6 +436,9 @@ public class UIDefaultsDump
dumpValue( out, strKey, value );
out.println();
} );
if( contrastRatios )
dumpContrastRatios( out );
}
private void dumpActionMaps( PrintWriter out ) {
@@ -829,6 +840,124 @@ public class UIDefaultsDump
return new Color( newColor.getRGB(), true );
}
private void dumpContrastRatios( PrintWriter out ) {
out.printf( "%n%n#-------- Contrast Ratios --------%n%n" );
out.println( "# WCAG 2 Contrast Requirements: minimum 4.5; enhanced 7.0" );
out.println( "# https://webaim.org/articles/contrast/#sc143" );
out.println();
HashMap<String, String> fg2bgMap = new HashMap<>();
defaults.keySet().stream()
.filter( key -> key instanceof String && ((String)key).endsWith( "ackground" ) )
.map( key -> (String) key )
.forEach( bgKey -> {
String fgKey = bgKey.replace( "Background", "Foreground" ).replace( "background", "foreground" );
fg2bgMap.put( fgKey, bgKey );
} );
// special cases
fg2bgMap.remove( "Button.disabledForeground" );
fg2bgMap.put( "Button.disabledText", "Button.disabledBackground" );
fg2bgMap.remove( "ToggleButton.disabledForeground" );
fg2bgMap.put( "ToggleButton.disabledText", "ToggleButton.disabledBackground" );
fg2bgMap.put( "CheckBox.foreground", "Panel.background" );
fg2bgMap.put( "CheckBox.disabledText", "Panel.background" );
fg2bgMap.put( "Label.foreground", "Panel.background" );
fg2bgMap.put( "Label.disabledForeground", "Panel.background" );
fg2bgMap.remove( "ProgressBar.foreground" );
fg2bgMap.put( "ProgressBar.selectionForeground", "ProgressBar.foreground" );
fg2bgMap.put( "ProgressBar.selectionBackground", "ProgressBar.background" );
fg2bgMap.put( "RadioButton.foreground", "Panel.background" );
fg2bgMap.put( "RadioButton.disabledText", "Panel.background" );
fg2bgMap.remove( "ScrollBar.foreground" );
fg2bgMap.remove( "ScrollBar.hoverButtonForeground" );
fg2bgMap.remove( "ScrollBar.pressedButtonForeground" );
fg2bgMap.remove( "ScrollPane.foreground" );
fg2bgMap.remove( "Separator.foreground" );
fg2bgMap.remove( "Slider.foreground" );
fg2bgMap.remove( "SplitPane.foreground" );
fg2bgMap.remove( "TextArea.disabledForeground" );
fg2bgMap.put( "TextArea.inactiveForeground", "TextArea.disabledBackground" );
fg2bgMap.remove( "TextPane.disabledForeground" );
fg2bgMap.put( "TextPane.inactiveForeground", "TextPane.disabledBackground" );
fg2bgMap.remove( "EditorPane.disabledForeground" );
fg2bgMap.put( "EditorPane.inactiveForeground", "EditorPane.disabledBackground" );
fg2bgMap.remove( "TextField.disabledForeground" );
fg2bgMap.put( "TextField.inactiveForeground", "TextField.disabledBackground" );
fg2bgMap.remove( "FormattedTextField.disabledForeground" );
fg2bgMap.put( "FormattedTextField.inactiveForeground", "FormattedTextField.disabledBackground" );
fg2bgMap.remove( "PasswordField.disabledForeground" );
fg2bgMap.put( "PasswordField.inactiveForeground", "PasswordField.disabledBackground" );
fg2bgMap.remove( "ToolBar.dockingForeground" );
fg2bgMap.remove( "ToolBar.floatingForeground" );
fg2bgMap.remove( "ToolBar.foreground" );
fg2bgMap.remove( "ToolBar.hoverButtonGroupForeground" );
fg2bgMap.remove( "Viewport.foreground" );
fg2bgMap.remove( "InternalFrame.closeHoverForeground" );
fg2bgMap.remove( "InternalFrame.closePressedForeground" );
fg2bgMap.remove( "TabbedPane.closeHoverForeground" );
fg2bgMap.remove( "TabbedPane.closePressedForeground" );
fg2bgMap.remove( "TitlePane.closeHoverForeground" );
fg2bgMap.remove( "TitlePane.closePressedForeground" );
// out.println();
// fg2bgMap.entrySet().stream()
// .sorted( (e1, e2) -> e1.getKey().compareTo( e2.getKey() ) )
// .forEach( e -> {
// out.printf( "%-50s %s%n", e.getKey(), e.getValue() );
// } );
// out.println();
AtomicReference<String> lastSubkey = new AtomicReference<>();
fg2bgMap.entrySet().stream()
.sorted( (e1, e2) -> {
String key1 = e1.getKey();
String key2 = e2.getKey();
int dot1 = key1.lastIndexOf( '.' );
int dot2 = key2.lastIndexOf( '.' );
if( dot1 < 0 || dot2 < 0 )
return key1.compareTo( key2 );
int r = key1.substring( dot1 + 1 ).compareTo( key2.substring( dot2 + 1 ) );
if( r != 0 )
return r;
return key1.substring( 0, dot1 ).compareTo( key2.substring( 0, dot2 ) );
} )
.forEach( e -> {
String fgKey = e.getKey();
String bgKey = e.getValue();
Color background = defaults.getColor( bgKey );
Color foreground = defaults.getColor( fgKey );
if( background != null && foreground != null ) {
float luma1 = ColorFunctions.luma( background );
float luma2 = ColorFunctions.luma( foreground );
float contrastRatio = (luma1 > luma2)
? (luma1 + 0.05f) / (luma2 + 0.05f)
: (luma2 + 0.05f) / (luma1 + 0.05f);
String rateing =
contrastRatio < 1.95f ? " !!!!!!" :
contrastRatio < 2.95f ? " !!!!!" :
contrastRatio < 3.95f ? " !!!!" :
contrastRatio < 4.95f ? " !!!" :
contrastRatio < 5.95f ? " !!" :
contrastRatio < 6.95f ? " !" :
"";
String subkey = fgKey.substring( fgKey.lastIndexOf( '.' ) + 1 );
if( !subkey.equals( lastSubkey.get() ) ) {
lastSubkey.set( subkey );
out.println();
out.println( "#-- " + subkey + " --" );
}
out.printf( "%-50s #%06x #%06x %4.1f%s%n", fgKey,
foreground.getRGB() & 0xffffff, background.getRGB() & 0xffffff,
contrastRatio, rateing );
}
} );
}
//---- class MyBasicLookAndFeel -------------------------------------------
public static class MyBasicLookAndFeel