mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 22:47:13 -06:00
Testing: FlatPaintingStringTest:
- added "Fonts" combobox to test various fonts - reworked/fixed text painting/sizing to get correct results
This commit is contained in:
@@ -22,12 +22,14 @@ import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.Arrays;
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.text.StyleContext;
|
||||
import com.formdev.flatlaf.FlatLaf;
|
||||
import com.formdev.flatlaf.FlatSystemProperties;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.JavaCompatibility;
|
||||
@@ -57,18 +59,49 @@ public class FlatPaintingStringTest
|
||||
FlatPaintingStringTest() {
|
||||
initComponents();
|
||||
|
||||
String[] availableFontFamilyNames = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||
.getAvailableFontFamilyNames().clone();
|
||||
Arrays.sort( availableFontFamilyNames );
|
||||
|
||||
Font currentFont = UIManager.getFont( "Label.font" );
|
||||
String currentFamily = currentFont.getFamily();
|
||||
|
||||
// initialize font families combobox
|
||||
String[] families = {
|
||||
"Arial", "Cantarell", "DejaVu Sans",
|
||||
"Dialog", "Inter", "Liberation Sans", "Noto Sans", "Open Sans", "Roboto",
|
||||
"SansSerif", "Segoe UI", "Tahoma", "Ubuntu", "Verdana" };
|
||||
Arrays.sort( families, String.CASE_INSENSITIVE_ORDER );
|
||||
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
|
||||
model.addElement( currentFamily );
|
||||
for( String family : families ) {
|
||||
if( !family.equals( currentFamily ) && Arrays.binarySearch( availableFontFamilyNames, family ) >= 0 )
|
||||
model.addElement( family );
|
||||
}
|
||||
fontField.setModel( model );
|
||||
fontField.setSelectedItem( currentFamily );
|
||||
updateFontMetricsLabel();
|
||||
|
||||
add( new JLabel() );
|
||||
add( new JLabel( "none" ) );
|
||||
add( new JLabel( "flatlaf" ) );
|
||||
add( new JLabel( "0.25*scale" ) );
|
||||
add( new JLabel( "0.5*scale" ) );
|
||||
add( new JLabel() );
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
add( new JLabel( "0.125" ) );
|
||||
add( new JLabel( "0.25" ) );
|
||||
add( new JLabel( "0.5" ) );
|
||||
add( new JLabel( "0.625" ) );
|
||||
add( new JLabel( "0.75" ) );
|
||||
add( new JLabel( "0.875" ) );
|
||||
add( new JLabel( "1" ) );
|
||||
add( new JLabel( "1.25" ) );
|
||||
add( new JLabel() );
|
||||
add( new JLabel( "0.25*scale" ) );
|
||||
add( new JLabel( "0.5*scale" ) );
|
||||
add( new JLabel( "ty" ) );
|
||||
} else {
|
||||
add( new JLabel( "0.25*scale" ) );
|
||||
add( new JLabel( "0.5*scale" ) );
|
||||
add( new JLabel( "0.625*scale" ) );
|
||||
add( new JLabel( "0.75*scale" ) );
|
||||
add( new JLabel( "0.875*scale" ) );
|
||||
@@ -80,16 +113,14 @@ public class FlatPaintingStringTest
|
||||
? HiDPIUtils.computeTextYCorrection( g )
|
||||
: (scaleFactor > 1 ? -(0.625f * scaleFactor) : 0);
|
||||
};
|
||||
YCorrectionFunction oneQSysScale = (g, scaleFactor) -> -(0.25f * scaleFactor);
|
||||
YCorrectionFunction halfSysScale = (g, scaleFactor) -> -(0.5f * scaleFactor);
|
||||
YCorrectionFunction fiveEightsQSysScale = (g, scaleFactor) -> -(0.625f * scaleFactor);
|
||||
YCorrectionFunction threeQSysScale = (g, scaleFactor) -> -(0.75f * scaleFactor);
|
||||
YCorrectionFunction sevenEightsSysScale = (g, scaleFactor) -> -(0.875f * scaleFactor);
|
||||
YCorrectionFunction oneQ = (g, scaleFactor) -> -0.25f;
|
||||
YCorrectionFunction half = (g, scaleFactor) -> -0.5f;
|
||||
YCorrectionFunction fiveEights = (g, scaleFactor) -> -0.625f;
|
||||
YCorrectionFunction threeQ = (g, scaleFactor) -> -0.75f;
|
||||
YCorrectionFunction sevenEights = (g, scaleFactor) -> -0.875f;
|
||||
YCorrectionFunction ty = (g, scaleFactor) -> {
|
||||
// Based on translateY, which is the scaled Y coordinate translation of the graphics context.
|
||||
// When painting whole window, translateY is from top of window, and this works fine.
|
||||
// But when repainting only parts of the window, then translateY starts somewhere
|
||||
// else and the text if (re-)painted at the wrong Y location.
|
||||
double y = g.getTransform().getTranslateY();
|
||||
return (float) -(y - (int) y);
|
||||
};
|
||||
|
||||
float[] scaleFactors = new float[] { 1f, 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 3f, 3.5f, 4f };
|
||||
|
||||
@@ -98,34 +129,72 @@ public class FlatPaintingStringTest
|
||||
|
||||
add( scaleFactor, none );
|
||||
add( scaleFactor, flatlaf );
|
||||
add( scaleFactor, oneQSysScale );
|
||||
add( scaleFactor, halfSysScale );
|
||||
add( new JLabel( " " ) );
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
add( scaleFactor, oneQ );
|
||||
add( scaleFactor, half );
|
||||
add( scaleFactor, fiveEights );
|
||||
add( scaleFactor, threeQ );
|
||||
add( scaleFactor, sevenEights );
|
||||
add( scaleFactor, (g, sf) -> -0.125f );
|
||||
add( scaleFactor, (g, sf) -> -0.25f );
|
||||
add( scaleFactor, (g, sf) -> -0.5f );
|
||||
add( scaleFactor, (g, sf) -> -0.625f );
|
||||
add( scaleFactor, (g, sf) -> -0.75f );
|
||||
add( scaleFactor, (g, sf) -> -0.875f );
|
||||
add( scaleFactor, (g, sf) -> -1f );
|
||||
add( scaleFactor, (g, sf) -> -1.25f );
|
||||
add( new JLabel( " " ) );
|
||||
add( scaleFactor, (g, sf) -> -(0.25f * sf) );
|
||||
add( scaleFactor, (g, sf) -> -(0.5f * sf) );
|
||||
add( scaleFactor, ty );
|
||||
} else {
|
||||
add( scaleFactor, fiveEightsQSysScale );
|
||||
add( scaleFactor, threeQSysScale );
|
||||
add( scaleFactor, sevenEightsSysScale );
|
||||
add( scaleFactor, (g, sf) -> -(0.25f * sf) );
|
||||
add( scaleFactor, (g, sf) -> -(0.5f * sf) );
|
||||
add( scaleFactor, (g, sf) -> -(0.625f * sf) );
|
||||
add( scaleFactor, (g, sf) -> -(0.75f * sf) );
|
||||
add( scaleFactor, (g, sf) -> -(0.875f * sf) );
|
||||
}
|
||||
|
||||
add( new JLabel( String.valueOf( scaleFactor ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void add( float scaleFactor, YCorrectionFunction correctionFunction ) {
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
add( new Painter( scaleFactor, correctionFunction, 0 ), "split 4, gapx 0 0" );
|
||||
add( new Painter( scaleFactor, correctionFunction, 0.25f ), "gapx 0 0" );
|
||||
add( new Painter( scaleFactor, correctionFunction, 0.5f ), "gapx 0 0" );
|
||||
add( new Painter( scaleFactor, correctionFunction, 0.75f ), "gapx 0 0" );
|
||||
add( new Painter( scaleFactor, correctionFunction, 1 ), "gapx 0 0" );
|
||||
add( new Painter( scaleFactor, correctionFunction, 2 ), "gapx 0 0" );
|
||||
add( new Painter( scaleFactor, correctionFunction, 3 ), "gapx 0 0" );
|
||||
} else
|
||||
add( new Painter( scaleFactor, correctionFunction, 0 ) );
|
||||
}
|
||||
|
||||
private void fontChanged() {
|
||||
String family = (String) fontField.getSelectedItem();
|
||||
|
||||
Font font = UIManager.getFont( "defaultFont" );
|
||||
if( font.getFamily().equals( family ) )
|
||||
return;
|
||||
|
||||
Font newFont = StyleContext.getDefaultStyleContext().getFont( family, font.getStyle(), font.getSize() );
|
||||
UIManager.put( "defaultFont", newFont );
|
||||
updateFontMetricsLabel();
|
||||
|
||||
FlatLaf.updateUILater();
|
||||
}
|
||||
|
||||
private void updateFontMetricsLabel() {
|
||||
Font font = UIManager.getFont( "defaultFont" );
|
||||
FontMetrics fm = getFontMetrics( font );
|
||||
fontMetricsLabel.setText( String.format( "%s %d height %d ascent %d descent %d max ascent %d max descent %d leading %d",
|
||||
font.getFamily(), font.getSize(),
|
||||
fm.getHeight(), fm.getAscent(), fm.getDescent(),
|
||||
fm.getMaxAscent(), fm.getMaxDescent(), fm.getLeading()
|
||||
) );
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||
JPanel panel1 = new JPanel();
|
||||
JLabel fontLabel = new JLabel();
|
||||
fontField = new JComboBox<>();
|
||||
fontMetricsLabel = new JLabel();
|
||||
|
||||
//======== this ========
|
||||
setBorder(null);
|
||||
@@ -134,11 +203,40 @@ public class FlatPaintingStringTest
|
||||
// columns
|
||||
"[fill]",
|
||||
// rows
|
||||
"[top]unrel" +
|
||||
"[top]"));
|
||||
|
||||
//======== panel1 ========
|
||||
{
|
||||
panel1.setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
// columns
|
||||
"[fill]" +
|
||||
"[fill]" +
|
||||
"[fill]",
|
||||
// rows
|
||||
"[]"));
|
||||
|
||||
//---- fontLabel ----
|
||||
fontLabel.setText("Font:");
|
||||
panel1.add(fontLabel, "cell 0 0");
|
||||
|
||||
//---- fontField ----
|
||||
fontField.setMaximumRowCount(20);
|
||||
fontField.addActionListener(e -> fontChanged());
|
||||
panel1.add(fontField, "cell 1 0");
|
||||
|
||||
//---- fontMetricsLabel ----
|
||||
fontMetricsLabel.setText("text");
|
||||
panel1.add(fontMetricsLabel, "cell 2 0");
|
||||
}
|
||||
add(panel1, "north");
|
||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||
}
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||
private JComboBox<String> fontField;
|
||||
private JLabel fontMetricsLabel;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
|
||||
private interface YCorrectionFunction {
|
||||
@@ -152,17 +250,29 @@ public class FlatPaintingStringTest
|
||||
{
|
||||
private final float scaleFactor;
|
||||
private final YCorrectionFunction correctionFunction;
|
||||
private final float yOffset;
|
||||
private final int yOffset;
|
||||
|
||||
public Painter( float scaleFactor, YCorrectionFunction correctionFunction, float yOffset ) {
|
||||
public Painter( float scaleFactor, YCorrectionFunction correctionFunction, int yOffset ) {
|
||||
super( "E" );
|
||||
this.scaleFactor = scaleFactor;
|
||||
this.correctionFunction = correctionFunction;
|
||||
this.yOffset = yOffset;
|
||||
setBorder( new EmptyBorder( 2, 0, 2, 0 ) );
|
||||
|
||||
updateFont();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUI() {
|
||||
super.updateUI();
|
||||
updateFont();
|
||||
}
|
||||
|
||||
private void updateFont() {
|
||||
if( scaleFactor == 0 )
|
||||
return; // invoked from super constructor
|
||||
|
||||
if( !SystemInfo.isJava_9_orLater ) {
|
||||
Font font = getFont();
|
||||
Font font = UIManager.getFont( "defaultFont" );
|
||||
setFont( font.deriveFont( (float) Math.round( font.getSize() * scaleFactor ) ) );
|
||||
}
|
||||
}
|
||||
@@ -170,35 +280,36 @@ public class FlatPaintingStringTest
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
Dimension size = super.getPreferredSize();
|
||||
Insets insets = getInsets();
|
||||
int leftRight = insets.left + insets.right;
|
||||
return new Dimension(
|
||||
scale( size.width -leftRight ) + leftRight,
|
||||
scale( size.height ) );
|
||||
if( SystemInfo.isJava_9_orLater ) {
|
||||
// compute component size using JRE scaling
|
||||
//
|
||||
// The y offset is used to simulate different vertical component positions,
|
||||
// which may result in different component heights.
|
||||
// E.g. scaling following bounds by 150% results in different heights:
|
||||
// 0,0, 10,15 --> [x=0,y=0,width=15,height=22]
|
||||
// 0,1, 10,15 --> [x=0,y=1,width=15,height=23]
|
||||
Rectangle r = scaleTo1x( scaleFactor, 0, yOffset, size.width, size.height );
|
||||
return new Dimension( r.width, r.height );
|
||||
} else
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent( Graphics g ) {
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
// simulate component y position at a fraction
|
||||
if( scaleFactor > 1 && SystemInfo.isJava_9_orLater )
|
||||
g2.translate( 0, yOffset );
|
||||
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
Insets insets = getInsets();
|
||||
FontMetrics fm = getFontMetrics( getFont() );
|
||||
|
||||
// paint lines at 1x
|
||||
HiDPIUtils.paintAtScale1x( g2, 0, 0, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor2) -> {
|
||||
// g.setColor( Color.blue );
|
||||
// g.drawLine( 0, 0, width2, 0 );
|
||||
// g.drawLine( 0, height2 - 1, width2, height2 - 1 );
|
||||
g.setColor( Color.blue );
|
||||
g.drawLine( 0, 0, width2, 0 );
|
||||
g.drawLine( 0, height2 - 1, width2, height2 - 1 );
|
||||
|
||||
int baseline = (int) Math.round( (insets.top + fm.getAscent()) * scaleFactor2
|
||||
int baseline = (int) Math.round( fm.getAscent() * scaleFactor2
|
||||
* (SystemInfo.isJava_9_orLater ? scaleFactor : 1f) ) - 1;
|
||||
int topline = height2 - baseline - 1;
|
||||
|
||||
@@ -207,8 +318,15 @@ public class FlatPaintingStringTest
|
||||
g.drawLine( 0, topline, width2, topline );
|
||||
} );
|
||||
|
||||
// move x before scaling to have same left inset at all scale factors
|
||||
g.translate( insets.left, 0 );
|
||||
// simulate different vertical component positions
|
||||
if( yOffset > 0 && SystemInfo.isJava_9_orLater ) {
|
||||
double ty = yOffset * scaleFactor;
|
||||
ty -= (int) ty;
|
||||
if( ty == 0 )
|
||||
return; // no need to paint
|
||||
|
||||
g2.translate( 0, ty );
|
||||
}
|
||||
|
||||
// scale
|
||||
if( SystemInfo.isJava_9_orLater )
|
||||
@@ -232,21 +350,36 @@ public class FlatPaintingStringTest
|
||||
|
||||
// draw string
|
||||
g.setColor( getForeground() );
|
||||
int y = insets.top + fm.getAscent();
|
||||
int y = fm.getAscent();
|
||||
JavaCompatibility.drawStringUnderlineCharAt( this, cg, "E", -1, 0, y );
|
||||
|
||||
// set tooltip text
|
||||
if( getToolTipText() == null ) {
|
||||
AffineTransform t = g2.getTransform();
|
||||
double textY = t.getTranslateY() + (y * t.getScaleY());
|
||||
setToolTipText( textY + " + " + yCorrection + " = " + (textY + yCorrection) );
|
||||
}
|
||||
|
||||
FlatUIUtils.resetRenderingHints( g2, oldRenderingHints );
|
||||
AffineTransform t = g2.getTransform();
|
||||
double textY = t.getTranslateY() + (y * t.getScaleY());
|
||||
setToolTipText( textY + " + " + yCorrection + " = " + (textY + yCorrection) );
|
||||
}
|
||||
|
||||
private int scale( int value ) {
|
||||
return SystemInfo.isJava_9_orLater ? Math.round( value * scaleFactor ) : value;
|
||||
/**
|
||||
* Scales a rectangle in the same way as the JRE does in
|
||||
* sun.java2d.pipe.PixelToParallelogramConverter.fillRectangle(),
|
||||
* which is used by Graphics.fillRect().
|
||||
*
|
||||
* This is a copy of HiDPIUtils.scale()
|
||||
*/
|
||||
public static Rectangle scaleTo1x( double scaleFactor, int x, int y, int width, int height ) {
|
||||
double px = (x * scaleFactor);
|
||||
double py = (y * scaleFactor);
|
||||
|
||||
double newX = normalize( px );
|
||||
double newY = normalize( py );
|
||||
double newWidth = normalize( px + (width * scaleFactor) ) - newX;
|
||||
double newHeight = normalize( py + (height * scaleFactor) ) - newY;
|
||||
|
||||
return new Rectangle( (int) Math.floor( newX ), (int) Math.floor( newY ), (int) newWidth, (int) newHeight );
|
||||
}
|
||||
|
||||
private static double normalize( double value ) {
|
||||
return Math.floor( value + 0.25 ) + 0.25;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "7.0.5.0.404" Java: "17.0.2" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -9,10 +9,45 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "insets dialog,hidemode 3"
|
||||
"$columnConstraints": "[fill]"
|
||||
"$rowConstraints": "[top]"
|
||||
"$rowConstraints": "[top]unrel[top]"
|
||||
} ) {
|
||||
name: "this"
|
||||
"border": sfield com.jformdesigner.model.FormObject NULL_VALUE
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[fill][fill][fill]"
|
||||
"$rowConstraints": "[]"
|
||||
} ) {
|
||||
name: "panel1"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "fontLabel"
|
||||
"text": "Font:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JComboBox" ) {
|
||||
name: "fontField"
|
||||
"maximumRowCount": 20
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
"JavaCodeGenerator.typeParameters": "String"
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "fontChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "fontMetricsLabel"
|
||||
"text": "text"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 0"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "north"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 450, 300 )
|
||||
|
||||
Reference in New Issue
Block a user