support changing default font used for all components with automatic scaling UI if using larger font

This commit is contained in:
Karl Tauber
2020-03-31 12:15:51 +02:00
parent 60c6c5b37a
commit af89dd13c1
12 changed files with 400 additions and 192 deletions

View File

@@ -49,8 +49,10 @@ import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIDefaults.ActiveValue;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.text.html.HTMLEditorKit;
import com.formdev.flatlaf.util.SystemInfo;
@@ -345,14 +347,22 @@ public abstract class FlatLaf
uiFont = UIScale.applyCustomScaleFactor( uiFont );
// use active value for all fonts to allow changing fonts in all components
// (similar as in Nimbus L&F) with:
// UIManager.put( "defaultFont", myFont );
Object activeFont = new ActiveFont( 1 );
// override fonts
for( Object key : defaults.keySet() ) {
if( key instanceof String && (((String)key).endsWith( ".font" ) || ((String)key).endsWith( "Font" )) )
defaults.put( key, uiFont );
defaults.put( key, activeFont );
}
// use smaller font for progress bar
defaults.put( "ProgressBar.font", UIScale.scaleFont( uiFont, 0.85f ) );
defaults.put( "ProgressBar.font", new ActiveFont( 0.85f ) );
// set default font
defaults.put( "defaultFont", uiFont );
}
/**
@@ -562,4 +572,42 @@ public abstract class FlatLaf
return false;
}
//---- class ActiveFont ---------------------------------------------------
private static class ActiveFont
implements ActiveValue
{
private final float scaleFactor;
// cache (scaled) font
private Font font;
private Font lastDefaultFont;
ActiveFont( float scaleFactor ) {
this.scaleFactor = scaleFactor;
}
@Override
public Object createValue( UIDefaults table ) {
Font defaultFont = UIManager.getFont( "defaultFont" );
if( lastDefaultFont != defaultFont ) {
lastDefaultFont = defaultFont;
if( scaleFactor != 1 ) {
// scale font
int newFontSize = Math.round( defaultFont.getSize() * scaleFactor );
font = new FontUIResource( defaultFont.deriveFont( (float) newFontSize ) );
} else {
// make sure that font is a UIResource for LaF switching
font = (defaultFont instanceof UIResource)
? defaultFont
: new FontUIResource( defaultFont );
}
}
return font;
}
}
}

View File

@@ -24,6 +24,7 @@ import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.reflect.Method;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
@@ -48,12 +49,15 @@ import javax.swing.plaf.UIResource;
*
* 2) user scaling mode
*
* This mode is mainly for Java 8 compatibility, but is also used on Linux.
* This mode is mainly for Java 8 compatibility, but is also used on Linux
* or if the default font is changed.
* The user scale factor is computed based on the used font.
* The JRE does not scale anything.
* So we have to invoke {@link #scale(float)} where necessary.
* There is only one user scale factor for all displays.
* The user scale factor may change if the active LaF or "Label.font" has changed.
* The user scale factor may change if the active LaF, "defaultFont" or "Label.font" has changed.
* If system scaling mode is available the user scale factor is usually 1,
* but may be larger on Linux or if the default font is changed.
*
* @author Karl Tauber
*/
@@ -61,6 +65,20 @@ public class UIScale
{
private static final boolean DEBUG = false;
private static PropertyChangeSupport changeSupport;
public static void addPropertyChangeListener( PropertyChangeListener listener ) {
if( changeSupport == null )
changeSupport = new PropertyChangeSupport( UIScale.class );
changeSupport.addPropertyChangeListener( listener );
}
public static void removePropertyChangeListener( PropertyChangeListener listener ) {
if( changeSupport == null )
return;
changeSupport.removePropertyChangeListener( listener );
}
//---- system scaling (Java 9) --------------------------------------------
private static Boolean jreHiDPI;
@@ -110,27 +128,33 @@ public class UIScale
return;
initialized = true;
if( isUserScalingEnabled() ) {
// listener to update scale factor if LaF changed or if Label.font changed
// (e.g. option "Override default fonts" in IntelliJ IDEA)
PropertyChangeListener listener = new PropertyChangeListener() {
@Override
public void propertyChange( PropertyChangeEvent e ) {
String propName = e.getPropertyName();
if( "lookAndFeel".equals( propName ) ) {
if( !isUserScalingEnabled() )
return;
// listener to update scale factor if LaF changed, "defaultFont" or "Label.font" changed
PropertyChangeListener listener = new PropertyChangeListener() {
@Override
public void propertyChange( PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case "lookAndFeel":
// it is not necessary (and possible) to remove listener of old LaF defaults
if( e.getNewValue() instanceof LookAndFeel )
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( this );
updateScaleFactor();
} else if( "Label.font".equals( propName ) )
updateScaleFactor();
}
};
UIManager.addPropertyChangeListener( listener );
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( listener );
break;
updateScaleFactor();
}
case "defaultFont":
case "Label.font":
updateScaleFactor();
break;
}
}
};
UIManager.addPropertyChangeListener( listener );
UIManager.getDefaults().addPropertyChangeListener( listener );
UIManager.getLookAndFeelDefaults().addPropertyChangeListener( listener );
updateScaleFactor();
}
private static void updateScaleFactor() {
@@ -141,7 +165,9 @@ public class UIScale
// because even if we are on a HiDPI display it is not sure
// that a larger font size is set by the current LaF
// (e.g. can avoid large icons with small text)
Font font = UIManager.getFont( "Label.font" );
Font font = UIManager.getFont( "defaultFont" );
if( font == null )
font = UIManager.getFont( "Label.font" );
setUserScaleFactor( computeScaleFactor( font ) );
}
@@ -168,9 +194,6 @@ public class UIScale
}
private static boolean isUserScalingEnabled() {
if( isSystemScalingEnabled() && !SystemInfo.IS_LINUX )
return false; // disable user scaling if JRE scales
// same as in IntelliJ IDEA
String hidpi = System.getProperty( "hidpi" );
return (hidpi != null) ? Boolean.parseBoolean( hidpi ) : true;
@@ -197,14 +220,6 @@ public class UIScale
return new FontUIResource( font.deriveFont( (float) newFontSize ) );
}
/**
* Scales the given font.
*/
public static FontUIResource scaleFont( FontUIResource font, float scaleFactor ) {
int newFontSize = Math.round( font.getSize() * scaleFactor );
return new FontUIResource( font.deriveFont( (float) newFontSize ) );
}
/**
* Similar to sun.java2d.SunGraphicsEnvironment.getScaleFactor(String)
*/
@@ -242,10 +257,14 @@ public class UIScale
else // round scale factor to 1/4
scaleFactor = Math.round( scaleFactor * 4f ) / 4f;
float oldScaleFactor = UIScale.scaleFactor;
UIScale.scaleFactor = scaleFactor;
if( DEBUG )
System.out.println( "HiDPI scale factor " + scaleFactor );
if( changeSupport != null )
changeSupport.firePropertyChange( "userScaleFactor", oldScaleFactor, scaleFactor );
}
public static float scale( float value ) {