mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-07 06:20:53 +03:00
UIScale introduced
This commit is contained in:
@@ -25,6 +25,7 @@ import java.awt.Insets;
|
|||||||
import java.awt.Paint;
|
import java.awt.Paint;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.basic.BasicBorders;
|
import javax.swing.plaf.basic.BasicBorders;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Border for {@link javax.swing.JButton}.
|
* Border for {@link javax.swing.JButton}.
|
||||||
@@ -42,7 +43,7 @@ public class FlatButtonBorder
|
|||||||
|
|
||||||
float focusWidth = getFocusWidth();
|
float focusWidth = getFocusWidth();
|
||||||
float lineWidth = getLineWidth();
|
float lineWidth = getLineWidth();
|
||||||
float arc = 6; //TODO
|
float arc = UIScale.scale( 6f ); //TODO
|
||||||
|
|
||||||
g2.setPaint( getBorderColor( c ) );
|
g2.setPaint( getBorderColor( c ) );
|
||||||
FlatUIUtils.drawRoundRectangle( g2, x, y, width, height, focusWidth, lineWidth, arc );
|
FlatUIUtils.drawRoundRectangle( g2, x, y, width, height, focusWidth, lineWidth, arc );
|
||||||
@@ -66,7 +67,7 @@ public class FlatButtonBorder
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Insets getBorderInsets( Component c, Insets insets ) {
|
public Insets getBorderInsets( Component c, Insets insets ) {
|
||||||
int w = Math.round( getFocusWidth() + getLineWidth() );
|
int w = UIScale.round( getFocusWidth() + getLineWidth() );
|
||||||
|
|
||||||
insets = super.getBorderInsets( c, insets );
|
insets = super.getBorderInsets( c, insets );
|
||||||
insets.top += w;
|
insets.top += w;
|
||||||
@@ -78,11 +79,11 @@ public class FlatButtonBorder
|
|||||||
|
|
||||||
protected float getFocusWidth() {
|
protected float getFocusWidth() {
|
||||||
//TODO
|
//TODO
|
||||||
return 2;
|
return UIScale.scale( 2f );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected float getLineWidth() {
|
protected float getLineWidth() {
|
||||||
//TODO
|
//TODO
|
||||||
return 1;
|
return UIScale.scale( 1f );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import javax.swing.JComponent;
|
|||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.basic.BasicButtonUI;
|
import javax.swing.plaf.basic.BasicButtonUI;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
import sun.swing.SwingUtilities2;
|
import sun.swing.SwingUtilities2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,8 +62,8 @@ public class FlatButtonUI
|
|||||||
FlatUIUtils.setRenderingHints( g2 );
|
FlatUIUtils.setRenderingHints( g2 );
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
float focusWidth = 2;
|
float focusWidth = UIScale.scale( 2f );
|
||||||
float arc = 6;
|
float arc = UIScale.scale( 6f );
|
||||||
|
|
||||||
g2.setColor( getBackground( c ) );
|
g2.setColor( getBackground( c ) );
|
||||||
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
FlatUIUtils.fillRoundRectangle( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.formdev.flatlaf.util;
|
package com.formdev.flatlaf.util;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides information about the current system.
|
* Provides information about the current system.
|
||||||
@@ -29,11 +30,43 @@ public class SystemInfo
|
|||||||
public static final boolean IS_MAC;
|
public static final boolean IS_MAC;
|
||||||
public static final boolean IS_LINUX;
|
public static final boolean IS_LINUX;
|
||||||
|
|
||||||
|
public static final boolean IS_JAVA_9_OR_LATER;
|
||||||
|
|
||||||
|
public static final boolean IS_JETBRAINS_JVM;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
String osName = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH );
|
String osName = System.getProperty( "os.name" ).toLowerCase( Locale.ENGLISH );
|
||||||
|
|
||||||
IS_WINDOWS = osName.startsWith( "windows" );
|
IS_WINDOWS = osName.startsWith( "windows" );
|
||||||
IS_MAC = osName.startsWith( "mac" );
|
IS_MAC = osName.startsWith( "mac" );
|
||||||
IS_LINUX = osName.startsWith( "linux" );
|
IS_LINUX = osName.startsWith( "linux" );
|
||||||
|
|
||||||
|
int javaVersion = scanVersion( System.getProperty( "java.version" ) );
|
||||||
|
IS_JAVA_9_OR_LATER = (javaVersion >= toVersion( 9, 0, 0, 0 ));
|
||||||
|
|
||||||
|
IS_JETBRAINS_JVM = System.getProperty( "java.vm.vendor", "Unknown" )
|
||||||
|
.toLowerCase( Locale.ENGLISH ).contains( "jetbrains" );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int scanVersion( String version ) {
|
||||||
|
int major = 1;
|
||||||
|
int minor = 0;
|
||||||
|
int micro = 0;
|
||||||
|
int patch = 0;
|
||||||
|
try {
|
||||||
|
StringTokenizer st = new StringTokenizer( version, "._-+" );
|
||||||
|
major = Integer.parseInt( st.nextToken() );
|
||||||
|
minor = Integer.parseInt( st.nextToken() );
|
||||||
|
micro = Integer.parseInt( st.nextToken() );
|
||||||
|
patch = Integer.parseInt( st.nextToken() );
|
||||||
|
} catch( Exception ex ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return toVersion( major, minor, micro, patch );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int toVersion( int major, int minor, int micro, int patch ) {
|
||||||
|
return (major << 24) + (minor << 16) + (micro << 8) + patch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
188
flatlaf-core/src/main/java/com/formdev/flatlaf/util/UIScale.java
Normal file
188
flatlaf-core/src/main/java/com/formdev/flatlaf/util/UIScale.java
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.util;
|
||||||
|
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two scaling modes are supported for HiDPI displays:
|
||||||
|
*
|
||||||
|
* 1) system scaling mode
|
||||||
|
*
|
||||||
|
* This mode is supported since Java 9 on all platforms and in some Java 8 VMs
|
||||||
|
* (e.g. Apple and JetBrains). The JRE determines the scale factor per-display and
|
||||||
|
* adds a scaling transformation to the graphics object.
|
||||||
|
* E.g. invokes {@code java.awt.Graphics2D.scale( 1.5, 1.5 )} for 150%.
|
||||||
|
* So the JRE does the scaling itself.
|
||||||
|
* E.g. when you draw a 10px line, a 15px line is drawn on screen.
|
||||||
|
* The scale factor may be different for each connected display.
|
||||||
|
*
|
||||||
|
* 2) user scaling mode
|
||||||
|
*
|
||||||
|
* This mode is for Java 8 compatibility and can be removed when changing minimum
|
||||||
|
* required Java version to 9.
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
public class UIScale
|
||||||
|
{
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
//---- system scaling (Java 9) --------------------------------------------
|
||||||
|
|
||||||
|
private static Boolean jreHiDPI;
|
||||||
|
|
||||||
|
private static boolean isJreHiDPIEnabled() {
|
||||||
|
if( jreHiDPI != null )
|
||||||
|
return jreHiDPI;
|
||||||
|
|
||||||
|
jreHiDPI = false;
|
||||||
|
|
||||||
|
if( SystemInfo.IS_JAVA_9_OR_LATER ) {
|
||||||
|
// Java 9 and later supports per-monitor scaling
|
||||||
|
jreHiDPI = true;
|
||||||
|
} else if( SystemInfo.IS_JETBRAINS_JVM ) {
|
||||||
|
// IntelliJ IDEA ships its own JetBrains Java 8 JRE that may supports per-monitor scaling
|
||||||
|
// see com.intellij.ui.JreHiDpiUtil.isJreHiDPIEnabled()
|
||||||
|
try {
|
||||||
|
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||||
|
Class<?> sunGeClass = Class.forName( "sun.java2d.SunGraphicsEnvironment" );
|
||||||
|
if( sunGeClass.isInstance( ge ) ) {
|
||||||
|
Method m = sunGeClass.getDeclaredMethod( "isUIScaleOn" );
|
||||||
|
jreHiDPI = (Boolean) m.invoke( ge );
|
||||||
|
}
|
||||||
|
} catch( Throwable ex ) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return jreHiDPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- user scaling (Java 8) ----------------------------------------------
|
||||||
|
|
||||||
|
private static float scaleFactor = 1;
|
||||||
|
|
||||||
|
static {
|
||||||
|
if( isEnabled() ) {
|
||||||
|
// 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 ) ) {
|
||||||
|
// 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 );
|
||||||
|
|
||||||
|
updateScaleFactor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateScaleFactor() {
|
||||||
|
if( !isEnabled() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// use font size to calculate scale factor (instead of DPI)
|
||||||
|
// 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" );
|
||||||
|
|
||||||
|
// default font size
|
||||||
|
float fontSizeDivider = 12f;
|
||||||
|
|
||||||
|
if( SystemInfo.IS_WINDOWS ) {
|
||||||
|
// Windows LaF uses Tahoma font rather than the actual Windows system font (Segoe UI),
|
||||||
|
// and its size is always ca. 10% smaller than the actual system font size.
|
||||||
|
// Tahoma 11 is used at 100%
|
||||||
|
if( "Tahoma".equals( font.getFamily() ) )
|
||||||
|
fontSizeDivider = 11f;
|
||||||
|
} else if( SystemInfo.IS_LINUX ) {
|
||||||
|
// default font size for Unity and Gnome is 15
|
||||||
|
fontSizeDivider = 15f;
|
||||||
|
}
|
||||||
|
|
||||||
|
setUserScaleFactor( font.getSize() / fontSizeDivider );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isEnabled() {
|
||||||
|
if( isJreHiDPIEnabled() )
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getUserScaleFactor() {
|
||||||
|
return scaleFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setUserScaleFactor( float scaleFactor ) {
|
||||||
|
if( scaleFactor <= 1f )
|
||||||
|
scaleFactor = 1f;
|
||||||
|
else // round scale factor to 1/4
|
||||||
|
scaleFactor = Math.round( scaleFactor * 4f ) / 4f;
|
||||||
|
|
||||||
|
UIScale.scaleFactor = scaleFactor;
|
||||||
|
|
||||||
|
if( DEBUG )
|
||||||
|
System.out.println( "HiDPI scale factor " + scaleFactor );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float scale( float value ) {
|
||||||
|
return (scaleFactor == 1) ? value : (value * scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int scale( int value ) {
|
||||||
|
return (scaleFactor == 1) ? value : round( value * scaleFactor );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float unscale( float value ) {
|
||||||
|
return (scaleFactor == 1f) ? value : (value / scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int unscale( int value ) {
|
||||||
|
return (scaleFactor == 1f) ? value : round( value / scaleFactor );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int round( float value ) {
|
||||||
|
// subtracting 0.01 gives "better" results in some cases
|
||||||
|
// e.g. 2px * 125% = 2px instead of 3px
|
||||||
|
// or 1px * 150% = 1px instead of 2px
|
||||||
|
return Math.round( value - 0.01f );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,7 +37,7 @@ public class FlatComponentsTest
|
|||||||
|
|
||||||
JOptionPane.showMessageDialog( null,
|
JOptionPane.showMessageDialog( null,
|
||||||
new FlatComponentsTest(),
|
new FlatComponentsTest(),
|
||||||
"FlatComponentsTest",
|
"FlatComponentsTest (Java " + System.getProperty( "java.version" ) + ")",
|
||||||
JOptionPane.PLAIN_MESSAGE );
|
JOptionPane.PLAIN_MESSAGE );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user