mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-12 06:57:13 -06:00
fixed/improved vertical position of text when scaled on HiDPI screens on Windows when running on Java 9 or later
This commit is contained in:
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
@@ -28,6 +29,7 @@ import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicEditorPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JEditorPane}.
|
||||
@@ -119,6 +121,11 @@ public class FlatEditorPaneUI
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.Icon;
|
||||
@@ -29,7 +30,9 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.plaf.basic.BasicLabelUI;
|
||||
import javax.swing.text.View;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -124,6 +127,12 @@ public class FlatLabelUI
|
||||
BasicHTML.updateRenderer( c, text );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g, JComponent c ) {
|
||||
View v = (View) c.getClientProperty( BasicHTML.propertyKey );
|
||||
super.paint( (v != null) ? HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) : g, c );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
|
||||
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
@@ -33,6 +34,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicPasswordFieldUI;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
|
||||
@@ -153,7 +155,8 @@ public class FlatPasswordFieldUI
|
||||
FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme );
|
||||
FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground );
|
||||
paintCapsLock( g );
|
||||
super.paintSafely( g );
|
||||
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
protected void paintCapsLock( Graphics g ) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTextArea;
|
||||
@@ -27,6 +28,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTextAreaUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextArea}.
|
||||
@@ -89,6 +91,11 @@ public class FlatTextAreaUI
|
||||
FlatEditorPaneUI.propertyChange( getComponent(), e );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
@@ -38,6 +38,7 @@ import javax.swing.plaf.basic.BasicTextFieldUI;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
|
||||
@@ -146,7 +147,8 @@ public class FlatTextFieldUI
|
||||
protected void paintSafely( Graphics g ) {
|
||||
paintBackground( g, getComponent(), isIntelliJTheme );
|
||||
paintPlaceholder( g, getComponent(), placeholderForeground );
|
||||
super.paintSafely( g );
|
||||
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JEditorPane;
|
||||
@@ -26,6 +27,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicTextPaneUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextPane}.
|
||||
@@ -99,6 +101,11 @@ public class FlatTextPaneUI
|
||||
return FlatEditorPaneUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintSafely( Graphics g ) {
|
||||
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintBackground( Graphics g ) {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
@@ -29,6 +29,7 @@ import javax.swing.SwingUtilities;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.plaf.basic.BasicToolTipUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -130,7 +131,7 @@ public class FlatToolTipUI
|
||||
FlatUIUtils.drawString( c, g, line, leftToRight ? x : x2 - SwingUtilities.computeStringWidth( fm, line ), y );
|
||||
}
|
||||
} else
|
||||
super.paint( g, c );
|
||||
super.paint( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ), c );
|
||||
}
|
||||
|
||||
private boolean isMultiLine( JComponent c ) {
|
||||
|
||||
@@ -46,7 +46,6 @@ import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -449,23 +448,24 @@ public class FlatUIUtils
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the given string at the specified location using text properties
|
||||
* and anti-aliasing hints from the provided component.
|
||||
*
|
||||
* Use this method instead of Graphics.drawString() for correct anti-aliasing.
|
||||
*
|
||||
* Replacement for SwingUtilities2.drawString()
|
||||
* Draws the given string at the specified location.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
* <p>
|
||||
* Use this method instead of {@link Graphics#drawString(String, int, int)} for correct anti-aliasing.
|
||||
* <p>
|
||||
* Replacement for {@code SwingUtilities2.drawString()}.
|
||||
* Uses {@link HiDPIUtils#drawStringWithYCorrection(JComponent, Graphics2D, String, int, int)}.
|
||||
*/
|
||||
public static void drawString( JComponent c, Graphics g, String text, int x, int y ) {
|
||||
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, -1, x, y );
|
||||
HiDPIUtils.drawStringWithYCorrection( c, (Graphics2D) g, text, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the given string at the specified location underlining the specified
|
||||
* character. The provided component is used to query text properties and
|
||||
* anti-aliasing hints.
|
||||
*
|
||||
* Replacement for SwingUtilities2.drawStringUnderlineCharAt()
|
||||
* Draws the given string at the specified location underlining the specified character.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
* <p>
|
||||
* Replacement for {@code SwingUtilities2.drawStringUnderlineCharAt()}.
|
||||
* Uses {@link HiDPIUtils#drawStringUnderlineCharAtWithYCorrection(JComponent, Graphics2D, String, int, int, int)}.
|
||||
*/
|
||||
public static void drawStringUnderlineCharAt( JComponent c, Graphics g,
|
||||
String text, int underlinedIndex, int x, int y )
|
||||
@@ -487,7 +487,7 @@ public class FlatUIUtils
|
||||
};
|
||||
}
|
||||
|
||||
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
|
||||
HiDPIUtils.drawStringUnderlineCharAtWithYCorrection( c, (Graphics2D) g, text, underlinedIndex, x, y );
|
||||
}
|
||||
|
||||
public static boolean hasOpaqueBeenExplicitlySet( JComponent c ) {
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package com.formdev.flatlaf.util;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import javax.swing.JComponent;
|
||||
|
||||
/**
|
||||
@@ -95,4 +97,116 @@ public class HiDPIUtils
|
||||
private static double normalize( double value ) {
|
||||
return Math.floor( value + 0.25 ) + 0.25;
|
||||
}
|
||||
|
||||
|
||||
private static Boolean useTextYCorrection;
|
||||
|
||||
private static boolean useTextYCorrection() {
|
||||
if( useTextYCorrection == null )
|
||||
useTextYCorrection = Boolean.valueOf( System.getProperty( "flatlaf.useTextYCorrection", "true" ) );
|
||||
return useTextYCorrection;
|
||||
}
|
||||
|
||||
/**
|
||||
* When painting text on HiDPI screens and the JRE scales, then the text is
|
||||
* painted too far down on some operating systems.
|
||||
* The higher the system scale factor is, the more.
|
||||
* <p>
|
||||
* This methods computes a correction value for the Y position.
|
||||
*/
|
||||
public static float computeTextYCorrection( Graphics2D g ) {
|
||||
if( !useTextYCorrection() || !SystemInfo.IS_WINDOWS || !SystemInfo.IS_JAVA_9_OR_LATER )
|
||||
return 0;
|
||||
|
||||
AffineTransform t = g.getTransform();
|
||||
double scaleY = t.getScaleY();
|
||||
if( scaleY < 1.25 )
|
||||
return 0;
|
||||
|
||||
// Text is painted at slightly different Y positions depending on scale factor
|
||||
// and Y position of component.
|
||||
// The exact reason is not yet known (to me), but there are several factors:
|
||||
// - fractional scale factors result in fractional component Y device coordinates
|
||||
// - fractional text Y device coordinates are rounded for horizontal lines of characters
|
||||
// - maybe different rounding methods for drawing primitives (e.g. rectangle) and text
|
||||
// - Java adds 0.5 to X/Y positions in before drawing string in BufferedTextPipe.enqueueGlyphList()
|
||||
|
||||
// this is not the optimal solution, but works very good in most cases
|
||||
// (tested with class FlatPaintingStringTest on Windows 10 with font "Segoe UI")
|
||||
if( scaleY <= 1.25 )
|
||||
return -0.875f;
|
||||
if( scaleY <= 1.5 )
|
||||
return -0.625f;
|
||||
if( scaleY <= 1.75 )
|
||||
return -0.875f;
|
||||
if( scaleY <= 2.0 )
|
||||
return -0.75f;
|
||||
if( scaleY <= 2.25 )
|
||||
return -0.875f;
|
||||
if( scaleY <= 3.5 )
|
||||
return -0.75f;
|
||||
return -0.875f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies Y correction and draws the given string at the specified location.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
* <p>
|
||||
* Use this method instead of {@link Graphics#drawString(String, int, int)} for correct anti-aliasing.
|
||||
* <p>
|
||||
* Replacement for {@code SwingUtilities2.drawString()}.
|
||||
*/
|
||||
public static void drawStringWithYCorrection( JComponent c, Graphics2D g, String text, int x, int y ) {
|
||||
drawStringUnderlineCharAtWithYCorrection( c, g, text, -1, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies Y correction and draws the given string at the specified location underlining the specified character.
|
||||
* The provided component is used to query text properties and anti-aliasing hints.
|
||||
* <p>
|
||||
* Replacement for {@code SwingUtilities2.drawStringUnderlineCharAt()}.
|
||||
*/
|
||||
public static void drawStringUnderlineCharAtWithYCorrection( JComponent c,
|
||||
Graphics2D g, String text, int underlinedIndex, int x, int y )
|
||||
{
|
||||
float yCorrection = computeTextYCorrection( g );
|
||||
if( yCorrection != 0 ) {
|
||||
g.translate( 0, yCorrection );
|
||||
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
|
||||
g.translate( 0, -yCorrection );
|
||||
} else
|
||||
JavaCompatibility.drawStringUnderlineCharAt( c, g, text, underlinedIndex, x, y );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a graphics object and applies Y correction to string drawing methods.
|
||||
* If no Y correction is necessary, the passed in graphics object is returned.
|
||||
*/
|
||||
public static Graphics2D createGraphicsTextYCorrection( Graphics2D g ) {
|
||||
float yCorrection = computeTextYCorrection( g );
|
||||
if( yCorrection == 0 )
|
||||
return g;
|
||||
|
||||
return new Graphics2DProxy( g ) {
|
||||
@Override
|
||||
public void drawString( String str, int x, int y ) {
|
||||
super.drawString( str, x, y + yCorrection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( String str, float x, float y ) {
|
||||
super.drawString( str, x, y + yCorrection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, int x, int y ) {
|
||||
super.drawString( iterator, x, y + yCorrection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString( AttributedCharacterIterator iterator, float x, float y ) {
|
||||
super.drawString( iterator, x, y + yCorrection );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user