From d34619824c9cdef2b2f37fc70187e2982d47ed60 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 17 Oct 2021 16:54:05 +0200 Subject: [PATCH] Typography: support deriving font from any other font (was always from defaultFont) (issue #384) --- .../java/com/formdev/flatlaf/FlatLaf.java | 40 ++++++++++++++----- .../com/formdev/flatlaf/UIDefaultsLoader.java | 13 ++++-- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index f5311895..a78f4a1e 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -527,7 +527,7 @@ public abstract class FlatLaf // use active value for all fonts to allow changing fonts in all components with: // UIManager.put( "defaultFont", myFont ); // (this is similar as in Nimbus L&F) - Object activeFont = new ActiveFont( null, -1, 0, 0, 0, 0 ); + Object activeFont = new ActiveFont( null, null, -1, 0, 0, 0, 0 ); // override fonts for( Object key : defaults.keySet() ) { @@ -611,7 +611,7 @@ public abstract class FlatLaf /** @since 1.1 */ public static ActiveValue createActiveFontValue( float scaleFactor ) { - return new ActiveFont( null, -1, 0, 0, 0, scaleFactor ); + return new ActiveFont( null, null, -1, 0, 0, 0, scaleFactor ); } /** @@ -1182,6 +1182,7 @@ public abstract class FlatLaf static class ActiveFont implements ActiveValue { + private final String baseFontKey; private final List families; private final int style; private final int styleChange; @@ -1191,7 +1192,9 @@ public abstract class FlatLaf // cache (scaled/derived) font private FontUIResource font; - private Font lastDefaultFont; + private Font lastBaseFont; + + private boolean inCreateValue; /** * @param families list of font families, or {@code null} @@ -1202,9 +1205,10 @@ public abstract class FlatLaf * @param relativeSize added to size of base font, or {@code 0} * @param scaleSize multiply size of base font, or {@code 0} */ - ActiveFont( List families, int style, int styleChange, + ActiveFont( String baseFontKey, List families, int style, int styleChange, int absoluteSize, int relativeSize, float scaleSize ) { + this.baseFontKey = baseFontKey; this.families = families; this.style = style; this.styleChange = styleChange; @@ -1215,16 +1219,30 @@ public abstract class FlatLaf @Override public Object createValue( UIDefaults table ) { - Font defaultFont = UIManager.getFont( "defaultFont" ); + if( inCreateValue ) + throw new IllegalStateException( "FlatLaf: endless recursion in font" ); - // fallback (to avoid NPE in case that this is used in another Laf) - if( defaultFont == null ) - defaultFont = UIManager.getFont( "Label.font" ); + Font baseFont = null; - if( lastDefaultFont != defaultFont ) { - lastDefaultFont = defaultFont; + inCreateValue = true; + try { + if( baseFontKey != null ) + baseFont = (Font) UIDefaultsLoader.lazyUIManagerGet( baseFontKey ); - font = derive( defaultFont, fontSize -> UIScale.scale( fontSize ) ); + if( baseFont == null ) + baseFont = UIManager.getFont( "defaultFont" ); + + // fallback (to avoid NPE in case that this is used in another Laf) + if( baseFont == null ) + baseFont = UIManager.getFont( "Label.font" ); + } finally { + inCreateValue = false; + } + + if( lastBaseFont != baseFont ) { + lastBaseFont = baseFont; + + font = derive( baseFont, fontSize -> UIScale.scale( fontSize ) ); } return font; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java index 95544e59..01b93eb6 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java @@ -1000,7 +1000,7 @@ class UIDefaultsLoader } /** - * Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [|+|-|%] [family[, family]] + * Syntax: [normal] [bold|+bold|-bold] [italic|+italic|-italic] [|+|-|%] [family[, family]] [$baseFontKey] */ private static Object parseFont( String value ) { Object font = fontCache.get( value ); @@ -1013,6 +1013,7 @@ class UIDefaultsLoader int relativeSize = 0; float scaleSize = 0; List families = null; + String baseFontKey = null; // use StreamTokenizer to split string because it supports quoted strings StreamTokenizer st = new StreamTokenizer( new StringReader( value ) ); @@ -1062,6 +1063,12 @@ class UIDefaultsLoader scaleSize = parseInteger( param.substring( 0, param.length() - 1 ), true ) / 100f; else absoluteSize = parseInteger( param, true ); + } else if( firstChar == '$' ) { + // reference to base font + if( baseFontKey != null ) + throw new IllegalArgumentException( "baseFontKey specified more than once in '" + value + "'" ); + + baseFontKey = param.substring( 1 ); } else { // font family if( families == null ) @@ -1088,7 +1095,7 @@ class UIDefaultsLoader throw new IllegalArgumentException( "can not use '+italic' and '-italic' in '" + value + "'" ); } - font = new FlatLaf.ActiveFont( families, style, styleChange, absoluteSize, relativeSize, scaleSize ); + font = new FlatLaf.ActiveFont( baseFontKey, families, style, styleChange, absoluteSize, relativeSize, scaleSize ); fontCache.put( value, font ); return font; } @@ -1227,7 +1234,7 @@ class UIDefaultsLoader * For use in LazyValue to get value for given key from UIManager and report error * if not found. If key is prefixed by '?', then no error is reported. */ - private static Object lazyUIManagerGet( String uiKey ) { + static Object lazyUIManagerGet( String uiKey ) { boolean optional = false; if( uiKey.startsWith( OPTIONAL_PREFIX ) ) { uiKey = uiKey.substring( OPTIONAL_PREFIX.length() );