Compare commits

..

23 Commits
0.9 ... 0.10

Author SHA1 Message Date
Karl Tauber
d0ac7867ae release 0.10 2019-10-07 11:16:11 +02:00
Karl Tauber
b6cd31b734 README.md: updated intro 2019-10-05 15:13:28 +02:00
Karl Tauber
8806cc8e93 Button: changed styling of default button in "Flat Light" theme (wide blue border instead of blue background) 2019-10-05 14:58:49 +02:00
Karl Tauber
2da0ca736f hide label, button and tab mnemonics by default and show them only when Alt is pressed (closes #4) 2019-10-05 11:46:22 +02:00
Karl Tauber
5288e0f54e introduced Component.innerFocusWidth UI default to allow "inner" focus border (e.g. if outer focus border width is zero)
currently zero in all themes because:
- undecided whether it is necessary
- not useful for "Flat IntelliJ" and "Flat Darcula" themes
- focused buttons in "Flat Light" theme already have light blue background
- does not work for components in scrollpanes (e.g. textarea)
2019-10-05 11:14:23 +02:00
Karl Tauber
c87f5cb05f Button: use bold font for default buttons in "Flat IntelliJ" and "Flat Darcula" themes 2019-10-05 11:03:18 +02:00
Karl Tauber
17074eb16d travis: added openjdk13 2019-10-04 19:31:59 +02:00
Karl Tauber
43429ddc39 hide label and button mnemonics on Mac (#4) 2019-10-04 19:26:09 +02:00
Karl Tauber
7ef598ded6 ComboBox: if not editable, then hover highlight arrow even if mouse is not in arrow button 2019-10-04 18:55:13 +02:00
Karl Tauber
37c70f6c9e Button: make icon-only buttons square (no minimum width, smaller left/right insets) 2019-10-04 18:18:53 +02:00
Karl Tauber
26a2446a4d FlatTestFrame: use same F-keys as in demo 2019-10-03 15:03:12 +02:00
Karl Tauber
771c949d74 Demo: update scale factor in info label when moving window to another screen 2019-10-03 14:49:11 +02:00
Karl Tauber
23d448d4fc FlatTestFrame: added scale factor combobox (Java 8 only) 2019-10-03 14:26:03 +02:00
Karl Tauber
86577c5fef FlatTestFrame: show scale factor in window title 2019-10-03 11:27:11 +02:00
Karl Tauber
3a69b41646 support specifying custom scale factor in system properties flatlaf.uiScale or sun.java2d.uiScale. E.g. -Dflatlaf.uiScale=1.5. (Java 8 only) 2019-10-03 10:23:15 +02:00
Karl Tauber
2d26b6fa94 SplitPane: scale one-touch buttons 2019-10-02 23:28:05 +02:00
Karl Tauber
144f79f0f9 chevron arrows implemented (closes #7)
use chevron arrows in "Flat Light" and "Flat Dark" themes, but keep triangle arrows in "Flat IntelliJ" and "Flat Darcula" themes
2019-10-02 19:13:47 +02:00
Karl Tauber
8ea23fc533 removed ModuleDepsTest.java 2019-10-01 19:39:25 +02:00
Karl Tauber
ae714502fb temporary added ModuleDepsTest.java, which uses module java.sql, to test whether compiler reports errors on Travis CI 2019-10-01 19:34:45 +02:00
Karl Tauber
07d6755ddb JPMS: compile main sources with module-info.java to make sure that compiler reports errors if classes are used from other modules that are not specified in module dependencies (#1) 2019-10-01 19:31:43 +02:00
Karl Tauber
177996ee81 JPMS: fix build running on Java 9 (#1) 2019-10-01 17:57:00 +02:00
Karl Tauber
3847b14033 support Java Platform Module System (JPMS) (issue #1) 2019-10-01 17:34:18 +02:00
Karl Tauber
423805be3a README.md: added maven coordinates 2019-09-28 14:01:25 +02:00
34 changed files with 712 additions and 87 deletions

View File

@@ -5,6 +5,7 @@ jdk:
- openjdk8
- openjdk9
- openjdk11
- openjdk13
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
@@ -24,5 +25,5 @@ deploy:
skip_cleanup: true # to upload artifacts created during the build
on:
branch: master
jdk: openjdk8
jdk: openjdk11
tags: true

View File

@@ -1,6 +1,25 @@
FlatLaf Change Log
==================
## 0.10
- Use new chevron arrows in "Flat Light" and "Flat Dark" themes, but keep
triangle arrows in "Flat IntelliJ" and "Flat Darcula" themes. (issue #7)
- Use bold font for default buttons in "Flat IntelliJ" and "Flat Darcula"
themes.
- Hide label, button and tab mnemonics by default and show them only when
<kbd>Alt</kbd> is pressed. (issue #4)
- If a JButton has an icon and no text, then it does not get a minimum width
(usually 72 pixel) and the left and right insets are same as top/bottom insets
so that it becomes square (if the icon is square).
- Changed styling of default button in "Flat Light" theme (wide blue border
instead of blue background).
- Added Java 9 module descriptor `module-info.class` to `flatlaf.jar` (in
`META-INF/versions/9`). But FlatLaf remains Java 8 compatible. (issue #1)
- Support specifying custom scale factor in system properties `flatlaf.uiScale`
or `sun.java2d.uiScale`. E.g. `-Dflatlaf.uiScale=1.5`. (Java 8 only)
## 0.9
- Initial release

View File

@@ -4,8 +4,9 @@ FlatLaf - Flat Look and Feel
**FlatLaf** is a modern open-source cross-platform Look and Feel for Java
desktop applications.
It is mostly "flat" (no shadows or gradients), clean, simple and elegant. It
comes with **Light** and **Dark** themes and is made for **HiDPI** displays.
It looks mostly "flat" (no shadows or gradients), clean, simple and elegant.
FlatLaf comes with **Light**, **Dark**, **IntelliJ** and **Darcula** themes,
scales on **HiDPI** displays and runs on Java 8 or newer.
The look is heavily inspired by **Darcula** and **IntelliJ** themes from
IntelliJ IDEA 2019.2+ and uses mostly the same colors and icons.
@@ -19,15 +20,22 @@ Demo
----
Download
[flatlaf-demo-0.1.jar](https://download.formdev.com/flatlaf/flatlaf-demo-0.1.jar)
and run it with `java -jar flatlaf-demo-0.1.jar` (or double-click it). Requires
[flatlaf-demo-0.10.jar](https://download.formdev.com/flatlaf/flatlaf-demo-0.10.jar)
and run it with `java -jar flatlaf-demo-0.10.jar` (or double-click it). Requires
Java 8 or newer.
Download
--------
Coming soon
[ ![Download](https://api.bintray.com/packages/jformdesigner/flatlaf/flatlaf-core/images/download.svg) ](https://bintray.com/jformdesigner/flatlaf/flatlaf-core/_latestVersion)
For Maven or Gradle use:
Repository: jcenter (https://jcenter.bintray.com/)
Group Id: com.formdev.flatlaf
Artifact Id: flatlaf-core
Version: 0.10
License

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
version = "0.9"
version = "0.10"
// check required Java version
if( JavaVersion.current() < JavaVersion.VERSION_1_8 )

View File

@@ -26,6 +26,18 @@ repositories {
jcenter()
}
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
sourceSets {
create( "module-info" ) {
java {
// include "src/main/java" here to get compile errors if classes are
// used from other modules that are not specified in module dependencies
setSrcDirs( listOf( "src/main/module-info", "src/main/java" ) )
}
}
}
}
dependencies {
testImplementation( "com.miglayout:miglayout-swing:5.2" )
testImplementation( "com.jgoodies:jgoodies-forms:1.9.0" )
@@ -37,8 +49,26 @@ java {
}
tasks {
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
named<JavaCompile>( "compileModuleInfoJava" ) {
sourceCompatibility = "9"
targetCompatibility = "9"
}
}
jar {
archiveBaseName.set( "flatlaf" )
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 ) {
manifest.attributes(
"Multi-Release" to "true"
)
into( "META-INF/versions/9" ) {
from( sourceSets["module-info"].output )
include( "module-info.class" )
}
}
}
javadoc {

View File

@@ -16,11 +16,18 @@
package com.formdev.flatlaf;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -29,7 +36,12 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Function;
import javax.swing.AbstractButton;
import javax.swing.JLabel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.UIDefaults.LazyValue;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.DimensionUIResource;
@@ -41,6 +53,7 @@ import com.formdev.flatlaf.ui.FlatEmptyBorder;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.util.ScaledNumber;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/**
* The base class for all Flat LaFs.
@@ -57,6 +70,9 @@ public abstract class FlatLaf
private BasicLookAndFeel base;
private AWTEventListener mnemonicListener;
private static boolean altKeyPressed;
@Override
public String getID() {
return getName();
@@ -77,10 +93,23 @@ public abstract class FlatLaf
getBase().initialize();
super.initialize();
// add mnemonic listener
mnemonicListener = e -> {
if( e instanceof KeyEvent && ((KeyEvent)e).getKeyCode() == KeyEvent.VK_ALT )
altKeyChanged( e.getID() == KeyEvent.KEY_PRESSED );
};
Toolkit.getDefaultToolkit().addAWTEventListener( mnemonicListener, AWTEvent.KEY_EVENT_MASK );
}
@Override
public void uninitialize() {
// remove mnemonic listener
if( mnemonicListener != null ) {
Toolkit.getDefaultToolkit().removeAWTEventListener( mnemonicListener );
mnemonicListener = null;
}
if( base != null )
base.uninitialize();
@@ -159,6 +188,8 @@ public abstract class FlatLaf
if( uiFont == null )
return;
uiFont = UIScale.applyCustomScaleFactor( uiFont );
// override fonts
for( Object key : defaults.keySet() ) {
if( key instanceof String && ((String)key).endsWith( ".font" ) )
@@ -285,15 +316,15 @@ public abstract class FlatLaf
key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
return parseInsets( value );
// size
if( key.endsWith( "Size" ) && !key.equals( "SplitPane.dividerSize" ))
return parseSize( value );
// scaled number
ScaledNumber scaledNumber = parseScaledNumber( key, value );
if( scaledNumber != null )
return scaledNumber;
// size
if( key.endsWith( "Size" ) && !key.equals( "SplitPane.dividerSize" ))
return parseSize( value );
// width, height
if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
return parseInteger( value, true );
@@ -400,8 +431,10 @@ public abstract class FlatLaf
}
private ScaledNumber parseScaledNumber( String key, String value ) {
if( !key.equals( "OptionPane.buttonMinimumWidth" ) )
return null; // not supported
if( !key.equals( "OptionPane.buttonMinimumWidth" ) &&
!key.equals( "SplitPane.oneTouchButtonSize" ) &&
!key.equals( "SplitPane.oneTouchButtonOffset" ) )
return null; // not supported
try {
return new ScaledNumber( Integer.parseInt( value ) );
@@ -424,4 +457,61 @@ public abstract class FlatLaf
return strs;
}
public static boolean isShowMnemonics() {
return altKeyPressed || !UIManager.getBoolean( "Component.hideMnemonics" );
}
private static void altKeyChanged( boolean pressed ) {
if( pressed == altKeyPressed )
return;
altKeyPressed = pressed;
// check whether it is necessary to repaint
if( !UIManager.getBoolean( "Component.hideMnemonics" ) )
return;
// get focus owner
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if( focusOwner == null )
return;
// get focused window
Window window = SwingUtilities.windowForComponent( focusOwner );
if( window == null )
return;
// repaint components with mnemonics in focused window
repaintMnemonics( window );
}
private static void repaintMnemonics( Container container ) {
for( Component c : container.getComponents() ) {
if( hasMnemonic( c ) )
c.repaint();
if( c instanceof Container )
repaintMnemonics( (Container) c );
}
}
private static boolean hasMnemonic( Component c ) {
if( c instanceof JLabel && ((JLabel)c).getDisplayedMnemonicIndex() >= 0 )
return true;
if( c instanceof AbstractButton && ((AbstractButton)c).getDisplayedMnemonicIndex() >= 0 )
return true;
if( c instanceof JTabbedPane ) {
JTabbedPane tabPane = (JTabbedPane) c;
int tabCount = tabPane.getTabCount();
for( int i = 0; i < tabCount; i++ ) {
if( tabPane.getDisplayedMnemonicIndexAt( i ) >= 0 )
return true;
}
}
return false;
}
}

View File

@@ -16,9 +16,11 @@
package com.formdev.flatlaf.icons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import javax.swing.JMenu;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
@@ -26,6 +28,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "arrow" icon for {@link javax.swing.JMenu}.
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Menu.icon.arrowColor Color
* @uiDefault Menu.icon.disabledArrowColor Color
* @uiDefault Menu.selectionForeground Color
@@ -35,12 +38,13 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatMenuArrowIcon
extends FlatAbstractIcon
{
protected final boolean chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
protected final Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
protected final Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" );
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
public FlatMenuArrowIcon() {
super( 5, 10, null );
super( 6, 10, null );
}
@Override
@@ -49,7 +53,15 @@ public class FlatMenuArrowIcon
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
g.setColor( getArrowColor( c ) );
g.fill( FlatUIUtils.createPath( 0,0.5, 0,9.5, 5,5 ) );
if( chevron ) {
// chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,1, 5,5, 1,9 );
g.setStroke( new BasicStroke( 1f ) );
g.draw( path );
} else {
// triangle arrow
g.fill( FlatUIUtils.createPath( 0,0.5, 0,9.5, 5,5 ) );
}
}
private Color getArrowColor( Component c ) {

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import javax.swing.UIManager;
@@ -24,6 +25,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "collapsed" icon for {@link javax.swing.JTree}.
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Tree.icon.collapsedColor Color
*
* @author Karl Tauber
@@ -31,15 +33,32 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatTreeCollapsedIcon
extends FlatAbstractIcon
{
private final boolean chevron;
public FlatTreeCollapsedIcon() {
super( 11, 11, UIManager.getColor( "Tree.icon.collapsedColor" ) );
this( UIManager.getColor( "Tree.icon.collapsedColor" ) );
}
FlatTreeCollapsedIcon( Color color ) {
super( 11, 11, color );
chevron = "chevron".equals( UIManager.getString( "Component.arrowType" ) );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
rotate( c, g );
if( chevron ) {
// chevron arrow
g.fill( FlatUIUtils.createPath( 3,1, 3,2.5, 6,5.5, 3,8.5, 3,10, 4.5,10, 9,5.5, 4.5,1 ) );
} else {
// triangle arrow
g.fill( FlatUIUtils.createPath( 2,1, 2,10, 10,5.5 ) );
}
}
void rotate( Component c, Graphics2D g ) {
if( !c.getComponentOrientation().isLeftToRight() )
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
g.fill( FlatUIUtils.createPath( 2,1, 2,10, 10,5.5 ) );
}
}

View File

@@ -19,7 +19,6 @@ package com.formdev.flatlaf.icons;
import java.awt.Component;
import java.awt.Graphics2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils;
/**
* "expanded" icon for {@link javax.swing.JTree}.
@@ -29,14 +28,14 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
* @author Karl Tauber
*/
public class FlatTreeExpandedIcon
extends FlatAbstractIcon
extends FlatTreeCollapsedIcon
{
public FlatTreeExpandedIcon() {
super( 11, 11, UIManager.getColor( "Tree.icon.expandedColor" ) );
super( UIManager.getColor( "Tree.icon.expandedColor" ) );
}
@Override
protected void paintIcon( Component c, Graphics2D g ) {
g.fill( FlatUIUtils.createPath( 1,2, 10,2, 5.5,10 ) );
void rotate( Component c, Graphics2D g ) {
g.rotate( Math.toRadians( 90 ), width / 2., height / 2. );
}
}

View File

@@ -17,6 +17,7 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
@@ -37,6 +38,7 @@ public class FlatArrowButton
extends BasicArrowButton
implements UIResource
{
private final boolean chevron;
private final Color foreground;
private final Color disabledForeground;
private final Color hoverForeground;
@@ -47,11 +49,12 @@ public class FlatArrowButton
private boolean hover;
public FlatArrowButton( int direction, Color foreground, Color disabledForeground,
public FlatArrowButton( int direction, String type, Color foreground, Color disabledForeground,
Color hoverForeground, Color hoverBackground )
{
super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE );
this.chevron = "chevron".equals( type );
this.foreground = foreground;
this.disabledForeground = disabledForeground;
this.hoverForeground = hoverForeground;
@@ -77,6 +80,10 @@ public class FlatArrowButton
}
}
protected boolean isHover() {
return hover;
}
public int getXOffset() {
return xOffset;
}
@@ -113,7 +120,7 @@ public class FlatArrowButton
boolean enabled = isEnabled();
// paint hover background
if( enabled && hover && hoverBackground != null ) {
if( enabled && isHover() && hoverBackground != null ) {
g.setColor( hoverBackground );
g.fillRect( 0, 0, width, height );
}
@@ -121,26 +128,41 @@ public class FlatArrowButton
int direction = getDirection();
boolean vert = (direction == NORTH || direction == SOUTH);
int w = scale( 9 );
int h = scale( 5 );
int x = Math.round( (width - (vert ? w : h)) / 2f + scale( (float) xOffset ) );
int y = Math.round( (height - (vert ? h : w)) / 2f + scale( (float) yOffset ) );
int w = scale( chevron ? 8 : 9 );
int h = scale( chevron ? 4 : 5 );
int rw = vert ? w : h;
int rh = vert ? h : w;
int x = Math.round( (width - rw) / 2f + scale( (float) xOffset ) );
int y = Math.round( (height - rh) / 2f + scale( (float) yOffset ) );
// optimization for small chevron arrows (e.g. OneTouchButtons in SplitPane)
if( x + rw >= width && x > 0 )
x--;
if( y + rh >= height && y > 0 )
y--;
// paint arrow
g.setColor( enabled
? (hover && hoverForeground != null ? hoverForeground : foreground)
? (isHover() && hoverForeground != null ? hoverForeground : foreground)
: disabledForeground );
g.translate( x, y );
g2.fill( createArrowShape( direction, w, h ) );
Shape arrowShape = createArrowShape( direction, chevron, w, h );
if( chevron ) {
g2.setStroke( new BasicStroke( scale( 1f ) ) );
g2.draw( arrowShape );
} else {
// triangle
g2.fill( arrowShape );
}
g.translate( -x, -y );
}
public static Shape createArrowShape( int direction, int w, int h ) {
public static Shape createArrowShape( int direction, boolean chevron, int w, int h ) {
switch( direction ) {
case NORTH: return FlatUIUtils.createPath( 0,h, w,h, (w / 2f),0 );
case SOUTH: return FlatUIUtils.createPath( 0,0, w,0, (w / 2f),h );
case WEST: return FlatUIUtils.createPath( h,0, h,w, 0,(w / 2f) );
case EAST: return FlatUIUtils.createPath( 0,0, 0,w, h,(w / 2f) );
case NORTH: return FlatUIUtils.createPath( !chevron, 0,h, (w / 2f),0, w,h );
case SOUTH: return FlatUIUtils.createPath( !chevron, 0,0, (w / 2f),h, w,0 );
case WEST: return FlatUIUtils.createPath( !chevron, h,0, 0,(w / 2f), h,w );
case EAST: return FlatUIUtils.createPath( !chevron, 0,0, h,(w / 2f), 0,w );
default: return new Path2D.Float();
}
}

View File

@@ -48,6 +48,7 @@ import javax.swing.text.JTextComponent;
* {@link FlatUIUtils#paintParentBackground} to paint the empty space correctly.
*
* @uiDefault Component.focusWidth int
* @uiDefault Component.innerFocusWidth int
* @uiDefault Component.focusColor Color
* @uiDefault Component.borderColor Color
* @uiDefault Component.disabledBorderColor Color
@@ -59,6 +60,7 @@ public class FlatBorder
extends BasicBorders.MarginBorder
{
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" );
protected final int innerFocusWidth = UIManager.getInt( "Component.innerFocusWidth" );
protected final Color focusColor = UIManager.getColor( "Component.focusColor" );
protected final Color borderColor = UIManager.getColor( "Component.borderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
@@ -71,16 +73,17 @@ public class FlatBorder
FlatUIUtils.setRenderingHints( g2 );
float focusWidth = getFocusWidth();
float lineWidth = getLineWidth();
float borderWidth = getBorderWidth( c );
float arc = getArc();
if( isFocused( c ) ) {
g2.setColor( getFocusColor( c ) );
FlatUIUtils.paintOutlineBorder( g2, x, y, width, height, focusWidth, lineWidth, arc );
FlatUIUtils.paintOutlineBorder( g2, x, y, width, height, focusWidth,
getLineWidth() + scale( (float) innerFocusWidth ), arc );
}
g2.setPaint( getBorderColor( c ) );
FlatUIUtils.drawRoundRectangle( g2, x, y, width, height, focusWidth, lineWidth, arc );
FlatUIUtils.drawRoundRectangle( g2, x, y, width, height, focusWidth, borderWidth, arc );
} finally {
g2.dispose();
}
@@ -149,6 +152,10 @@ public class FlatBorder
return scale( 1f );
}
protected float getBorderWidth( Component c ) {
return getLineWidth();
}
protected float getArc() {
return 0;
}

View File

@@ -20,8 +20,11 @@ import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Paint;
import javax.swing.JButton;
import javax.swing.UIManager;
import javax.swing.plaf.UIResource;
/**
* Border for {@link javax.swing.JButton}.
@@ -34,6 +37,7 @@ import javax.swing.UIManager;
* @uiDefault Button.default.hoverBorderColor Color optional
* @uiDefault Button.default.focusedBorderColor Color
* @uiDefault Button.default.focusColor Color
* @uiDefault Button.default.borderWidth int
* @uiDefault Button.arc int
*
* @author Karl Tauber
@@ -49,6 +53,7 @@ public class FlatButtonBorder
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
protected final int arc = UIManager.getInt( "Button.arc" );
@Override
@@ -73,6 +78,22 @@ public class FlatButtonBorder
null );
}
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
insets = super.getBorderInsets( c, insets );
// use smaller left and right insets for icon-only buttons (so that they are square)
if( FlatButtonUI.isIconOnlyButton( c ) && ((JButton)c).getMargin() instanceof UIResource )
insets.left = insets.right = Math.min( insets.top, insets.bottom );
return insets;
}
@Override
protected float getBorderWidth( Component c ) {
return FlatButtonUI.isDefaultButton( c ) ? scale( (float) defaultBorderWidth ) : super.getBorderWidth( c );
}
@Override
protected float getArc() {
return scale( (float) arc );

View File

@@ -21,6 +21,7 @@ import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
@@ -35,7 +36,9 @@ import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonUI;
import com.formdev.flatlaf.FlatLaf;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JButton}.
@@ -55,6 +58,7 @@ import javax.swing.plaf.basic.BasicButtonUI;
* @uiDefault Button.default.focusedBackground Color optional
* @uiDefault Button.default.hoverBackground Color optional
* @uiDefault Button.default.pressedBackground Color optional
* @uiDefault Button.default.boldText boolean
* @uiDefault Button.toolbar.hoverBackground Color
* @uiDefault Button.toolbar.pressedBackground Color
*
@@ -78,6 +82,7 @@ public class FlatButtonUI
protected Color defaultFocusedBackground;
protected Color defaultHoverBackground;
protected Color defaultPressedBackground;
protected boolean defaultBoldText;
protected Color toolbarHoverBackground;
protected Color toolbarPressedBackground;
@@ -116,6 +121,7 @@ public class FlatButtonUI
defaultFocusedBackground = UIManager.getColor( "Button.default.focusedBackground" );
defaultHoverBackground = UIManager.getColor( "Button.default.hoverBackground" );
defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" );
defaultBoldText = UIManager.getBoolean( "Button.default.boldText" );
toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" );
toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" );
@@ -146,6 +152,13 @@ public class FlatButtonUI
return c instanceof JButton && ((JButton)c).isDefaultButton();
}
static boolean isIconOnlyButton( Component c ) {
String text;
return c instanceof JButton &&
((JButton)c).getIcon() != null &&
((text = ((JButton)c).getText()) == null || text.isEmpty());
}
static boolean isHelpButton( Component c ) {
return c instanceof JButton && clientPropertyEquals( (JButton) c, BUTTON_TYPE, BUTTON_TYPE_HELP );
}
@@ -191,12 +204,23 @@ public class FlatButtonUI
if( isHelpButton( b ) )
return;
if( defaultBoldText && isDefaultButton( b ) && b.getFont() instanceof UIResource ) {
Font boldFont = g.getFont().deriveFont( Font.BOLD );
g.setFont( boldFont );
int boldWidth = b.getFontMetrics( boldFont ).stringWidth( text );
if( boldWidth > textRect.width ) {
textRect.x -= (boldWidth - textRect.width) / 2;
textRect.width = boldWidth;
}
}
paintText( g, b, textRect, text, b.isEnabled() ? getForeground( b ) : disabledText );
}
static void paintText( Graphics g, AbstractButton b, Rectangle textRect, String text, Color foreground ) {
FontMetrics fm = b.getFontMetrics( b.getFont() );
int mnemonicIndex = b.getDisplayedMnemonicIndex();
int mnemonicIndex = FlatLaf.isShowMnemonics() ? b.getDisplayedMnemonicIndex() : -1;
g.setColor( foreground );
FlatUIUtils.drawStringUnderlineCharAt( b, g, text, mnemonicIndex,
@@ -259,8 +283,11 @@ public class FlatButtonUI
return new Dimension( helpButtonIcon.getIconWidth(), helpButtonIcon.getIconHeight() );
Dimension prefSize = super.getPreferredSize( c );
if( !isToolBarButton( c ) )
// apply minimum width, if not in toolbar and not a icon-only button
if( !isToolBarButton( c ) && !isIconOnlyButton( c ) )
prefSize.width = Math.max( prefSize.width, scale( minimumWidth + (focusWidth * 2) ) );
return prefSize;
}
}

View File

@@ -29,6 +29,7 @@ import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@@ -57,6 +58,7 @@ import com.formdev.flatlaf.util.UIScale;
*
* @uiDefault Component.focusWidth int
* @uiDefault Component.arc int
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.borderColor Color
* @uiDefault Component.disabledBorderColor Color
* @uiDefault ComboBox.disabledBackground Color
@@ -74,6 +76,7 @@ public class FlatComboBoxUI
{
protected int focusWidth;
protected int arc;
protected String arrowType;
protected Color borderColor;
protected Color disabledBorderColor;
@@ -86,16 +89,42 @@ public class FlatComboBoxUI
protected Color buttonDisabledArrowColor;
protected Color buttonHoverArrowColor;
private MouseListener hoverListener;
private boolean hover;
public static ComponentUI createUI( JComponent c ) {
return new FlatComboBoxUI();
}
@Override
protected void installListeners() {
super.installListeners();
hoverListener = new FlatUIUtils.HoverListener( null, h -> {
if( !comboBox.isEditable() ) {
hover = h;
if( arrowButton != null )
arrowButton.repaint();
}
} );
comboBox.addMouseListener( hoverListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
comboBox.removeMouseListener( hoverListener );
hoverListener = null;
}
@Override
protected void installDefaults() {
super.installDefaults();
focusWidth = UIManager.getInt( "Component.focusWidth" );
arc = UIManager.getInt( "Component.arc" );
arrowType = UIManager.getString( "Component.arrowType" );
borderColor = UIManager.getColor( "Component.borderColor" );
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
@@ -224,8 +253,14 @@ public class FlatComboBoxUI
@Override
protected JButton createArrowButton() {
return new FlatArrowButton( SwingConstants.SOUTH, buttonArrowColor,
buttonDisabledArrowColor, buttonHoverArrowColor, null );
return new FlatArrowButton( SwingConstants.SOUTH, arrowType, buttonArrowColor,
buttonDisabledArrowColor, buttonHoverArrowColor, null )
{
@Override
protected boolean isHover() {
return super.isHover() || (!comboBox.isEditable() ? hover : false);
}
};
}
@Override

View File

@@ -27,6 +27,7 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicLabelUI;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -71,9 +72,16 @@ public class FlatLabelUI
defaults_initialized = false;
}
@Override
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;
g.setColor( l.getForeground() );
FlatUIUtils.drawStringUnderlineCharAt( l, g, s, mnemIndex, textX, textY );
}
@Override
protected void paintDisabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
int mnemIndex = l.getDisplayedMnemonicIndex();
int mnemIndex = FlatLaf.isShowMnemonics() ? l.getDisplayedMnemonicIndex() : -1;
g.setColor( disabledForeground );
FlatUIUtils.drawStringUnderlineCharAt( l, g, s, mnemIndex, textX, textY );
}

View File

@@ -48,6 +48,7 @@ import javax.swing.plaf.basic.BasicSpinnerUI;
* @uiDefault Component.focusWidth int
* @uiDefault Component.arc int
* @uiDefault Component.minimumWidth int
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault Component.borderColor Color
* @uiDefault Component.disabledBorderColor Color
* @uiDefault Spinner.disabledBackground Color
@@ -68,6 +69,7 @@ public class FlatSpinnerUI
protected int focusWidth;
protected int arc;
protected int minimumWidth;
protected String arrowType;
protected Color borderColor;
protected Color disabledBorderColor;
protected Color disabledBackground;
@@ -89,6 +91,7 @@ public class FlatSpinnerUI
focusWidth = UIManager.getInt( "Component.focusWidth" );
arc = UIManager.getInt( "Component.arc" );
minimumWidth = UIManager.getInt( "Component.minimumWidth" );
arrowType = UIManager.getString( "Component.arrowType" );
borderColor = UIManager.getColor( "Component.borderColor" );
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
disabledBackground = UIManager.getColor( "Spinner.disabledBackground" );
@@ -209,7 +212,7 @@ public class FlatSpinnerUI
}
private Component createArrowButton( int direction, String name ) {
FlatArrowButton button = new FlatArrowButton( direction, buttonArrowColor,
FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor,
buttonDisabledArrowColor, buttonHoverArrowColor, null );
button.setName( name );
button.setYOffset( (direction == SwingConstants.NORTH) ? 1 : -1 );

View File

@@ -31,6 +31,7 @@ import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JSplitPane}.
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault SplitPane.background Color
* @uiDefault SplitPane.foreground Color unused
* @uiDefault SplitPane.dividerSize int
@@ -46,6 +47,7 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatSplitPaneUI
extends BasicSplitPaneUI
{
protected String arrowType;
private Boolean continuousLayout;
private Color oneTouchArrowColor;
private Color oneTouchHoverArrowColor;
@@ -56,6 +58,8 @@ public class FlatSplitPaneUI
@Override
protected void installDefaults() {
arrowType = UIManager.getString( "Component.arrowType" );
// get one-touch colors before invoking super.installDefaults() because they are
// used in there on LaF switching
oneTouchArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchArrowColor" );
@@ -108,7 +112,7 @@ public class FlatSplitPaneUI
private final boolean left;
public FlatOneTouchButton( boolean left ) {
super( SwingConstants.NORTH, oneTouchArrowColor, null, oneTouchHoverArrowColor, null );
super( SwingConstants.NORTH, arrowType, oneTouchArrowColor, null, oneTouchHoverArrowColor, null );
setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) );
this.left = left;

View File

@@ -33,12 +33,14 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
import javax.swing.text.View;
import com.formdev.flatlaf.FlatLaf;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTabbedPane}.
*
* @clientProperty JTabbedPane.hasFullBorder boolean
*
* @uiDefault Component.arrowType String triangle (default) or chevron
* @uiDefault TabbedPane.font Font
* @uiDefault TabbedPane.background Color
* @uiDefault TabbedPane.foreground Color
@@ -144,7 +146,8 @@ public class FlatTabbedPaneUI
@Override
protected JButton createScrollButton( int direction ) {
// this method is invoked before installDefaults(), so we can not use color fields here
return new FlatArrowButton( direction, UIManager.getColor("TabbedPane.shadow"),
return new FlatArrowButton( direction, UIManager.getString( "Component.arrowType" ),
UIManager.getColor( "TabbedPane.shadow" ),
UIManager.getColor( "TabbedPane.disabledForeground" ), null,
UIManager.getColor( "TabbedPane.hoverColor" ) );
}
@@ -261,7 +264,7 @@ public class FlatTabbedPaneUI
} else
color = disabledForeground;
int mnemIndex = tabPane.getDisplayedMnemonicIndexAt( tabIndex );
int mnemIndex = FlatLaf.isShowMnemonics() ? tabPane.getDisplayedMnemonicIndexAt( tabIndex ) : -1;
g.setColor( color );
FlatUIUtils.drawStringUnderlineCharAt( tabPane, g, title, mnemIndex,

View File

@@ -181,11 +181,16 @@ public class FlatUIUtils
}
public static Path2D createPath( double... points ) {
return createPath( true, points );
}
public static Path2D createPath( boolean close, double... points ) {
Path2D path = new Path2D.Float();
path.moveTo( points[0], points[1] );
for( int i = 2; i < points.length; i += 2 )
path.lineTo( points[i], points[i + 1] );
path.closePath();
if( close )
path.closePath();
return path;
}

View File

@@ -28,6 +28,7 @@ import java.lang.reflect.Method;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.DimensionUIResource;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.UIResource;
@@ -65,7 +66,7 @@ public class UIScale
private static Boolean jreHiDPI;
private static boolean isJreHiDPIEnabled() {
public static boolean isJreHiDPIEnabled() {
if( jreHiDPI != null )
return jreHiDPI;
@@ -103,8 +104,13 @@ public class UIScale
//---- user scaling (Java 8) ----------------------------------------------
private static float scaleFactor = 1;
private static boolean initialized;
private static void initialize() {
if( initialized )
return;
initialized = true;
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)
@@ -138,6 +144,10 @@ public class UIScale
// (e.g. can avoid large icons with small text)
Font font = UIManager.getFont( "Label.font" );
setUserScaleFactor( computeScaleFactor( font ) );
}
private static float computeScaleFactor( Font font ) {
// default font size
float fontSizeDivider = 12f;
@@ -152,7 +162,7 @@ public class UIScale
fontSizeDivider = 15f;
}
setUserScaleFactor( font.getSize() / fontSizeDivider );
return font.getSize() / fontSizeDivider;
}
private static boolean isEnabled() {
@@ -164,7 +174,58 @@ public class UIScale
return (hidpi != null) ? Boolean.parseBoolean( hidpi ) : true;
}
/**
* Applies a custom scale factor given in system properties "flatlaf.uiScale"
* or "sun.java2d.uiScale" to the given font.
*/
public static FontUIResource applyCustomScaleFactor( FontUIResource font ) {
if( UIScale.isJreHiDPIEnabled() )
return font;
String uiScale = System.getProperty( "flatlaf.uiScale" );
if( uiScale == null )
uiScale = System.getProperty( "sun.java2d.uiScale" );
float scaleFactor = parseScaleFactor( uiScale );
if( scaleFactor <= 0 )
return font;
float fontScaleFactor = computeScaleFactor( font );
if( scaleFactor == fontScaleFactor )
return font;
int newFontSize = Math.round( (font.getSize() / fontScaleFactor) * scaleFactor );
return new FontUIResource( font.getFamily(), font.getStyle(), newFontSize );
}
/**
* Similar to sun.java2d.SunGraphicsEnvironment.getScaleFactor(String)
*/
private static float parseScaleFactor( String s ) {
if( s == null )
return -1;
float units = 1;
if( s.endsWith( "x" ) )
s = s.substring( 0, s.length() - 1 );
else if( s.endsWith( "dpi" ) ) {
units = 96;
s = s.substring( 0, s.length() - 3 );
} else if( s.endsWith( "%" ) ) {
units = 100;
s = s.substring( 0, s.length() - 1 );
}
try {
float scale = Float.parseFloat( s );
return scale > 0 ? scale / units : -1;
} catch( NumberFormatException ex ) {
return -1;
}
}
public static float getUserScaleFactor() {
initialize();
return scaleFactor;
}
@@ -181,10 +242,12 @@ public class UIScale
}
public static float scale( float value ) {
initialize();
return (scaleFactor == 1) ? value : (value * scaleFactor);
}
public static int scale( int value ) {
initialize();
return (scaleFactor == 1) ? value : Math.round( value * scaleFactor );
}
@@ -192,23 +255,28 @@ public class UIScale
* Similar as scale(int) but always "rounds down".
*/
public static int scale2( int value ) {
initialize();
return (scaleFactor == 1) ? value : (int) (value * scaleFactor);
}
public static float unscale( float value ) {
initialize();
return (scaleFactor == 1f) ? value : (value / scaleFactor);
}
public static int unscale( int value ) {
initialize();
return (scaleFactor == 1f) ? value : Math.round( value / scaleFactor );
}
public static void scaleGraphics( Graphics2D g ) {
initialize();
if( scaleFactor != 1f )
g.scale( scaleFactor, scaleFactor );
}
public static Dimension scale( Dimension dimension ) {
initialize();
return (dimension == null || scaleFactor == 1f)
? dimension
: (dimension instanceof UIResource
@@ -217,6 +285,7 @@ public class UIScale
}
public static Insets scale( Insets insets ) {
initialize();
return (insets == null || scaleFactor == 1f)
? insets
: (insets instanceof UIResource

View File

@@ -0,0 +1,27 @@
/*
* 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.
*/
/**
* @author Karl Tauber
*/
module com.formdev.flatlaf {
requires java.desktop;
exports com.formdev.flatlaf;
exports com.formdev.flatlaf.icons;
exports com.formdev.flatlaf.ui;
exports com.formdev.flatlaf.util;
}

View File

@@ -18,9 +18,16 @@
# which is licensed under the Apache 2.0 license. Copyright 2000-2019 JetBrains s.r.o.
# See: https://github.com/JetBrains/intellij-community/
#---- Button ----
Button.default.boldText=true
#---- Component ----
Component.focusWidth=2
Component.innerFocusWidth=0
Component.arrowType=triangle
#---- RadioButton ----

View File

@@ -79,6 +79,7 @@ Button.default.borderColor=4c708c
Button.default.hoverBorderColor=537699
Button.default.focusedBorderColor=537699
Button.default.focusColor=43688c
Button.default.boldText=true
Button.toolbar.hoverBackground=4c5052
Button.toolbar.pressedBackground=555a5d

View File

@@ -22,6 +22,17 @@
Button.focusedBackground=null
Button.default.background=4A86C7
Button.default.foreground=f0f0f0
Button.default.focusedBackground=null
Button.default.hoverBackground=5B91CC
Button.default.pressedBackground=6E9ED2
Button.default.borderColor=3167ad
Button.default.hoverBorderColor=a8cef6
Button.default.focusedBorderColor=a8cef6
Button.default.focusColor=97c3f3
Button.default.boldText=true
#---- CheckBox ----
@@ -37,6 +48,8 @@ CheckBox.icon.selectedPressedBackground=72A1D4
#---- Component ----
Component.focusWidth=2
Component.innerFocusWidth=0
Component.arrowType=triangle
#---- RadioButton ----

View File

@@ -70,6 +70,8 @@ Button.iconTextGap=4
Button.rollover=true
Button.defaultButtonFollowsFocus=false
Button.default.borderWidth=1
#---- CheckBox ----
@@ -103,8 +105,11 @@ ComboBox.padding=2,6,2,6
#---- Component ----
Component.focusWidth=0
Component.innerFocusWidth=0
Component.arc=5
Component.minimumWidth=64
Component.arrowType=chevron
Component.hideMnemonics=true
#---- EditorPane ----
@@ -306,6 +311,8 @@ SplitPane.dividerSize=5
SplitPane.continuousLayout=true
SplitPane.border=null
SplitPane.centerOneTouchButtons=true
SplitPane.oneTouchButtonSize=6
SplitPane.oneTouchButtonOffset=2
SplitPaneDivider.border=null
SplitPaneDivider.oneTouchArrowColor=@@ComboBox.buttonArrowColor

View File

@@ -72,14 +72,16 @@ Button.disabledBorderColor=cfcfcf
Button.focusedBorderColor=87afda
Button.hoverBorderColor=@@Button.focusedBorderColor
Button.default.background=4A86C7
Button.default.foreground=f0f0f0
Button.default.hoverBackground=5B91CC
Button.default.pressedBackground=6E9ED2
Button.default.borderColor=3167ad
Button.default.hoverBorderColor=a8cef6
Button.default.focusedBorderColor=a8cef6
Button.default.focusColor=97c3f3
Button.default.background=@@Button.background
Button.default.foreground=@foreground
Button.default.focusedBackground=@@Button.focusedBackground
Button.default.hoverBackground=@@Button.hoverBackground
Button.default.pressedBackground=@@Button.pressedBackground
Button.default.borderColor=4D89C9
Button.default.hoverBorderColor=@@Button.hoverBorderColor
Button.default.focusedBorderColor=@@Button.focusedBorderColor
Button.default.focusColor=@@Component.focusColor
Button.default.borderWidth=2
Button.toolbar.hoverBackground=dfdfdf
Button.toolbar.pressedBackground=d8d8d8

View File

@@ -55,6 +55,7 @@ public class FlatComponentsTest
FlatComponentsTest.TestDefaultButton button5 = new FlatComponentsTest.TestDefaultButton();
JButton button3 = new JButton();
JButton button12 = new JButton();
JButton button13 = new JButton();
JLabel toggleButtonLabel = new JLabel();
JToggleButton toggleButton1 = new JToggleButton();
JToggleButton toggleButton2 = new JToggleButton();
@@ -246,6 +247,10 @@ public class FlatComponentsTest
button12.setEnabled(false);
add(button12, "cell 4 1");
//---- button13 ----
button13.setIcon(UIManager.getIcon("Tree.closedIcon"));
add(button13, "cell 5 1");
//---- toggleButtonLabel ----
toggleButtonLabel.setText("JToggleButton:");
add(toggleButtonLabel, "cell 0 2");

View File

@@ -76,6 +76,12 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "button13"
"icon": new com.jformdesigner.model.SwingIcon( 2, "Tree.closedIcon" )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "toggleButtonLabel"
"text": "JToggleButton:"

View File

@@ -17,13 +17,19 @@
package com.formdev.flatlaf;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.prefs.Preferences;
import javax.swing.*;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*;
/**
@@ -34,18 +40,28 @@ public class FlatTestFrame
{
private static final String PREFS_ROOT_PATH = "/flatlaf-test";
private static final String KEY_LAF = "laf";
private static final String KEY_SCALE_FACTOR = "scaleFactor";
private final String title;
private JComponent content;
private FlatInspector inspector;
public static FlatTestFrame create( String[] args, String title ) {
Preferences prefs = Preferences.userRoot().node( PREFS_ROOT_PATH );
// set scale factor
if( System.getProperty( "flatlaf.uiScale", System.getProperty( "sun.java2d.uiScale" ) ) == null ) {
String scaleFactor = prefs.get( KEY_SCALE_FACTOR, null );
if( scaleFactor != null )
System.setProperty( "flatlaf.uiScale", scaleFactor );
}
// set look and feel
try {
if( args.length > 0 )
UIManager.setLookAndFeel( args[0] );
else {
String lafClassName = Preferences.userRoot().node( PREFS_ROOT_PATH )
.get( KEY_LAF, FlatLightLaf.class.getName() );
String lafClassName = prefs.get( KEY_LAF, FlatLightLaf.class.getName() );
UIManager.setLookAndFeel( lafClassName );
}
} catch( Exception ex ) {
@@ -60,21 +76,21 @@ public class FlatTestFrame
}
// create frame
FlatTestFrame frame = new FlatTestFrame();
frame.setTitle( title + " (Java " + System.getProperty( "java.version" ) + ")" );
return frame;
return new FlatTestFrame( title );
}
private FlatTestFrame() {
private FlatTestFrame( String title ) {
this.title = title;
initComponents();
// initialize look and feels combo box
DefaultComboBoxModel<LafInfo> lafModel = new DefaultComboBoxModel<>();
lafModel.addElement( new LafInfo( "Flat Light (F1)", FlatLightLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat Dark (F2)", FlatDarkLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat Test (F3)", FlatTestLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat IntelliJ (F4)", FlatIntelliJLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat Darcula (F5)", FlatDarculaLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat IntelliJ (F3)", FlatIntelliJLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat Darcula (F4)", FlatDarculaLaf.class.getName() ) );
lafModel.addElement( new LafInfo( "Flat Test (F8)", FlatTestLaf.class.getName() ) );
UIManager.LookAndFeelInfo[] lookAndFeels = UIManager.getInstalledLookAndFeels();
for( UIManager.LookAndFeelInfo lookAndFeel : lookAndFeels ) {
@@ -106,12 +122,18 @@ public class FlatTestFrame
lookAndFeelComboBox.setModel( lafModel );
// register F1, F2 and F3 keys to switch to Light, Dark or Test LaF
updateScaleFactorComboBox();
String scaleFactor = System.getProperty( "flatlaf.uiScale", System.getProperty( "sun.java2d.uiScale" ) );
if( scaleFactor != null )
scaleFactorComboBox.setSelectedItem( scaleFactor );
// register F1, F2, ... keys to switch to Light, Dark or other LaFs
registerSwitchToLookAndFeel( KeyEvent.VK_F1, FlatLightLaf.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F2, FlatDarkLaf.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F3, FlatTestLaf.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F4, FlatIntelliJLaf.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F5, FlatDarculaLaf.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F3, FlatIntelliJLaf.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F4, FlatDarculaLaf.class.getName() );
registerSwitchToLookAndFeel( KeyEvent.VK_F8, FlatTestLaf.class.getName() );
if( SystemInfo.IS_WINDOWS )
registerSwitchToLookAndFeel( KeyEvent.VK_F9, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" );
@@ -130,6 +152,35 @@ public class FlatTestFrame
// close frame
closeButton.addActionListener(e -> dispose());
// update title
addWindowListener( new WindowAdapter() {
@Override
public void windowOpened( WindowEvent e ) {
updateTitle();
}
} );
// update title when moved to another screen
addComponentListener( new ComponentAdapter() {
@Override
public void componentMoved( ComponentEvent e ) {
updateTitle();
}
} );
}
private void updateTitle() {
double systemScaleFactor = UIScale.getSystemScaleFactor( getGraphicsConfiguration() );
float userScaleFactor = UIScale.getUserScaleFactor();
String newTitle = title + " (Java " + System.getProperty( "java.version" )
+ (systemScaleFactor != 1 ? ("; system scale factor " + systemScaleFactor) : "")
+ (userScaleFactor != 1 ? ("; user scale factor " + userScaleFactor) : "")
+ (systemScaleFactor == 1 && userScaleFactor == 1 ? "; no scaling" : "")
+ ")";
if( !newTitle.equals( getTitle() ) )
setTitle( newTitle );
}
private void registerSwitchToLookAndFeel( int keyCode, String lafClassName ) {
@@ -169,22 +220,54 @@ public class FlatTestFrame
if( newLaf.className.equals( UIManager.getLookAndFeel().getClass().getName() ) )
return;
// hide popup to avoid occasional StackOverflowError when updating UI
lookAndFeelComboBox.setPopupVisible( false );
Preferences.userRoot().node( PREFS_ROOT_PATH ).put( KEY_LAF, newLaf.className );
applyLookAndFeel( newLaf.className, false );
}
private void applyLookAndFeel( String lafClassName, boolean pack ) {
EventQueue.invokeLater( () -> {
try {
// change look and feel
UIManager.setLookAndFeel( newLaf.className );
UIManager.setLookAndFeel( lafClassName );
// update title because user scale factor may change
updateTitle();
// enable/disable scale factor combobox
updateScaleFactorComboBox();
// update all components
SwingUtilities.updateComponentTreeUI( this );
// increase size of frame if necessary
int width = getWidth();
int height = getHeight();
Dimension prefSize = getPreferredSize();
if( prefSize.width > width || prefSize.height > height )
setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
if( pack )
pack();
else {
int width = getWidth();
int height = getHeight();
Dimension prefSize = getPreferredSize();
if( prefSize.width > width || prefSize.height > height )
setSize( Math.max( prefSize.width, width ), Math.max( prefSize.height, height ) );
}
// limit frame size to screen size
Rectangle screenBounds = getGraphicsConfiguration().getBounds();
screenBounds = FlatUIUtils.subtractInsets( screenBounds, getToolkit().getScreenInsets( getGraphicsConfiguration() ) );
Dimension frameSize = getSize();
if( frameSize.width > screenBounds.width || frameSize.height > screenBounds.height )
setSize( Math.min( frameSize.width, screenBounds.width ), Math.min( frameSize.height, screenBounds.height ) );
// move frame to left/top if necessary
if( getX() + getWidth() > screenBounds.x + screenBounds.width ||
getY() + getHeight() > screenBounds.y + screenBounds.height )
{
setLocation( Math.min( getX(), screenBounds.x + screenBounds.width - getWidth() ),
Math.min( getY(), screenBounds.y + screenBounds.height - getHeight() ) );
}
if( inspector != null )
inspector.update();
@@ -289,6 +372,31 @@ public class FlatTestFrame
inspector.setEnabled( inspectCheckBox.isSelected() );
}
private void scaleFactorChanged() {
String scaleFactor = (String) scaleFactorComboBox.getSelectedItem();
if( "default".equals( scaleFactor ) )
scaleFactor = null;
// hide popup to avoid occasional StackOverflowError when updating UI
scaleFactorComboBox.setPopupVisible( false );
Preferences prefs = Preferences.userRoot().node( PREFS_ROOT_PATH );
if( scaleFactor != null ) {
System.setProperty( "flatlaf.uiScale", scaleFactor );
prefs.put( KEY_SCALE_FACTOR, scaleFactor );
} else {
System.clearProperty( "flatlaf.uiScale" );
prefs.remove( KEY_SCALE_FACTOR );
}
applyLookAndFeel( UIManager.getLookAndFeel().getClass().getName(), true );
}
private void updateScaleFactorComboBox() {
scaleFactorComboBox.setEnabled( !UIScale.isJreHiDPIEnabled() && UIManager.getLookAndFeel() instanceof FlatLaf );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
dialogPane = new JPanel();
@@ -299,6 +407,7 @@ public class FlatTestFrame
rightToLeftCheckBox = new JCheckBox();
enabledCheckBox = new JCheckBox();
inspectCheckBox = new JCheckBox();
scaleFactorComboBox = new JComboBox<>();
closeButton = new JButton();
//======== this ========
@@ -332,6 +441,7 @@ public class FlatTestFrame
"[fill]" +
"[fill]" +
"[fill]" +
"[fill]" +
"[grow,fill]" +
"[button,fill]",
// rows
@@ -366,9 +476,27 @@ public class FlatTestFrame
inspectCheckBox.addActionListener(e -> inspectChanged());
buttonBar.add(inspectCheckBox, "cell 4 0");
//---- scaleFactorComboBox ----
scaleFactorComboBox.setModel(new DefaultComboBoxModel<>(new String[] {
"default",
"1",
"1.25",
"1.5",
"1.75",
"2.0",
"2.25",
"2.5",
"3",
"3.5",
"4"
}));
scaleFactorComboBox.setMaximumRowCount(20);
scaleFactorComboBox.addActionListener(e -> scaleFactorChanged());
buttonBar.add(scaleFactorComboBox, "cell 5 0");
//---- closeButton ----
closeButton.setText("Close");
buttonBar.add(closeButton, "cell 6 0");
buttonBar.add(closeButton, "cell 7 0");
}
dialogPane.add(buttonBar, BorderLayout.SOUTH);
}
@@ -385,6 +513,7 @@ public class FlatTestFrame
private JCheckBox rightToLeftCheckBox;
private JCheckBox enabledCheckBox;
private JCheckBox inspectCheckBox;
private JComboBox<String> scaleFactorComboBox;
private JButton closeButton;
// JFormDesigner - End of variables declaration //GEN-END:variables

View File

@@ -21,7 +21,7 @@ new FormModel {
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog"
"$columnConstraints": "[fill][fill][fill][fill][fill][grow,fill][button,fill]"
"$columnConstraints": "[fill][fill][fill][fill][fill][fill][grow,fill][button,fill]"
"$rowSpecs": "[fill]"
} ) {
name: "buttonBar"
@@ -67,11 +67,35 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 0"
} )
add( new FormComponent( "javax.swing.JComboBox" ) {
name: "scaleFactorComboBox"
"model": new javax.swing.DefaultComboBoxModel {
selectedItem: "default"
addElement( "default" )
addElement( "1" )
addElement( "1.25" )
addElement( "1.5" )
addElement( "1.75" )
addElement( "2.0" )
addElement( "2.25" )
addElement( "2.5" )
addElement( "3" )
addElement( "3.5" )
addElement( "4" )
}
"maximumRowCount": 20
auxiliary() {
"JavaCodeGenerator.typeParameters": "String"
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "scaleFactorChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "closeButton"
"text": "Close"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 6 0"
"value": "cell 7 0"
} )
}, new FormLayoutConstraints( class java.lang.String ) {
"value": "South"
@@ -81,7 +105,7 @@ new FormModel {
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 510, 300 )
"size": new java.awt.Dimension( 640, 300 )
} )
}
}

View File

@@ -42,6 +42,8 @@ tasks {
attributes( "Main-Class" to "com.formdev.flatlaf.demo.FlatLafDemo" )
}
exclude( "META-INF/versions/**" )
// include all dependencies in jar
from( {
configurations.runtimeClasspath.get().filter { it.name.endsWith( "jar" ) }.map { zipTree( it ) }

View File

@@ -39,6 +39,7 @@ class BasicComponentsPanel
JButton button2 = new JButton();
JButton button3 = new JButton();
JButton button4 = new JButton();
JButton button13 = new JButton();
JLabel checkBoxLabel = new JLabel();
JCheckBox checkBox1 = new JCheckBox();
JCheckBox checkBox2 = new JCheckBox();
@@ -169,6 +170,10 @@ class BasicComponentsPanel
button4.setEnabled(false);
add(button4, "cell 4 1");
//---- button13 ----
button13.setIcon(UIManager.getIcon("Tree.closedIcon"));
add(button13, "cell 5 1");
//---- checkBoxLabel ----
checkBoxLabel.setText("JCheckBox");
add(checkBoxLabel, "cell 0 2");

View File

@@ -69,6 +69,12 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "button13"
"icon": new com.jformdesigner.model.SwingIcon( 2, "Tree.closedIcon" )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "checkBoxLabel"
"text": "JCheckBox"

View File

@@ -17,6 +17,8 @@
package com.formdev.flatlaf.demo;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
@@ -106,15 +108,19 @@ class ControlBar
// make the "close" button the default button
frame.getRootPane().setDefaultButton( closeButton );
// move focus to "close" button
// update info label and move focus to "close" button
frame.addWindowListener( new WindowAdapter() {
@Override
public void windowOpened( WindowEvent e ) {
updateInfoLabel();
closeButton.requestFocusInWindow();
}
} );
// update info label when moved to another screen
frame.addComponentListener( new ComponentAdapter() {
@Override
public void windowActivated( WindowEvent e ) {
public void componentMoved( ComponentEvent e ) {
updateInfoLabel();
}
} );
@@ -123,11 +129,14 @@ class ControlBar
private void updateInfoLabel() {
double systemScaleFactor = UIScale.getSystemScaleFactor( getGraphicsConfiguration() );
float userScaleFactor = UIScale.getUserScaleFactor();
infoLabel.setText( "(Java " + System.getProperty( "java.version" )
String newInfo = "(Java " + System.getProperty( "java.version" )
+ (systemScaleFactor != 1 ? ("; system scale factor " + systemScaleFactor) : "")
+ (userScaleFactor != 1 ? ("; user scale factor " + userScaleFactor) : "")
+ (systemScaleFactor == 1 && userScaleFactor == 1 ? "; no scaling" : "")
+ ")" );
+ ")";
if( !newInfo.equals( infoLabel.getText() ) )
infoLabel.setText( newInfo );
}
private void registerSwitchToLookAndFeel( int keyCode, String lafClassName ) {