Merge PR #341: Styling individual components

This commit is contained in:
Karl Tauber
2021-09-15 20:00:06 +02:00
120 changed files with 7300 additions and 561 deletions

View File

@@ -3,6 +3,11 @@ FlatLaf Change Log
## 2.0-SNAPSHOT ## 2.0-SNAPSHOT
#### New features and improvements
- Styling components using string in CSS syntax or `java.util.Map`. (PR #341)\
For example: `mySlider.putClientProperty( "FlatLaf.style", "trackWidth: 2" );`
#### Fixed bugs #### Fixed bugs
- Tree: Fixed editing cell issue with custom cell renderer and cell editor that - Tree: Fixed editing cell issue with custom cell renderer and cell editor that

View File

@@ -126,6 +126,25 @@ public interface FlatClientProperties
//---- JComponent --------------------------------------------------------- //---- JComponent ---------------------------------------------------------
/**
* Specifies the style of a component as String in CSS syntax ("key1: value1; key2: value2; ...")
* or as {@link java.util.Map}<String, Object> with binary values.
* <p>
* The keys are the same as used in UI defaults, but without component type prefix.
* E.g. for UI default {@code Slider.thumbSize} use key {@code thumbSize}.
* <p>
* The syntax of the CSS values is the same as used in FlatLaf properties files
* (<a href="https://www.formdev.com/flatlaf/properties-files/">https://www.formdev.com/flatlaf/properties-files/</a>),
* but some features are not supported (e.g. variables).
* When using a map, the values are not parsed from a string. They must be binary.
* <p>
* <strong>Components</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.String} or {@link java.util.Map}&lt;String, Object&gt;<br>
*
* @since 2
*/
String STYLE = "FlatLaf.style";
/** /**
* Specifies minimum width of a component. * Specifies minimum width of a component.
* <p> * <p>

View File

@@ -32,6 +32,7 @@ import java.beans.PropertyChangeListener;
import java.io.File; import java.io.File;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -55,6 +56,7 @@ import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
import javax.swing.UIDefaults.ActiveValue; import javax.swing.UIDefaults.ActiveValue;
import javax.swing.UIDefaults.LazyValue;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException; import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
@@ -779,6 +781,34 @@ public abstract class FlatLaf
customDefaultsSources.remove( folder ); customDefaultsSources.remove( folder );
} }
/**
* Parses a UI defaults value string and converts it into a binary object.
* <p>
* See: <a href="https://www.formdev.com/flatlaf/properties-files/">https://www.formdev.com/flatlaf/properties-files/</a>
*
* @param key the key, which is used to determine the value type if parameter {@code valueType} is {@code null}
* @param value the value string
* @param valueType the expected value type, or {@code null}
* @return the binary value
* @throws IllegalArgumentException on syntax errors
* @since 2
*/
public static Object parseDefaultsValue( String key, String value, Class<?> valueType )
throws IllegalArgumentException
{
// parse value
Object val = UIDefaultsLoader.parseValue( key, value, valueType, null,
v -> UIDefaultsLoader.resolveValueFromUIManager( v ), Collections.emptyList() );
// create actual value if lazy or active
if( val instanceof LazyValue )
val = ((LazyValue)val).createValue( null );
else if( val instanceof ActiveValue )
val = ((ActiveValue)val).createValue( null );
return val;
}
private static void reSetLookAndFeel() { private static void reSetLookAndFeel() {
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); LookAndFeel lookAndFeel = UIManager.getLookAndFeel();

View File

@@ -338,7 +338,7 @@ public class IntelliJTheme
// parse value // parse value
try { try {
uiValue = UIDefaultsLoader.parseValue( key, valueStr ); uiValue = UIDefaultsLoader.parseValue( key, valueStr, null );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
UIDefaultsLoader.logParseError( key, valueStr, ex, false ); UIDefaultsLoader.logParseError( key, valueStr, ex, false );
return; // ignore invalid value return; // ignore invalid value

View File

@@ -33,8 +33,10 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.Icon;
import javax.swing.UIDefaults; import javax.swing.UIDefaults;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.UIDefaults.ActiveValue; import javax.swing.UIDefaults.ActiveValue;
import javax.swing.UIDefaults.LazyValue; import javax.swing.UIDefaults.LazyValue;
import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ColorUIResource;
@@ -241,7 +243,7 @@ class UIDefaultsLoader
String value = resolveValue( (String) e.getValue(), propertiesGetter ); String value = resolveValue( (String) e.getValue(), propertiesGetter );
try { try {
defaults.put( key, parseValue( key, value, null, resolver, addonClassLoaders ) ); defaults.put( key, parseValue( key, value, null, null, resolver, addonClassLoaders ) );
} catch( RuntimeException ex ) { } catch( RuntimeException ex ) {
logParseError( key, value, ex, true ); logParseError( key, value, ex, true );
} }
@@ -288,16 +290,36 @@ class UIDefaultsLoader
return resolveValue( newValue, propertiesGetter ); return resolveValue( newValue, propertiesGetter );
} }
static String resolveValueFromUIManager( String value ) {
if( !value.startsWith( PROPERTY_PREFIX ) )
return value;
String key = value.substring( PROPERTY_PREFIX.length() );
Object newValue = UIManager.get( key );
if( newValue == null )
throw new IllegalArgumentException( "property '" + key + "' not found" );
// convert binary color to string
if( newValue instanceof Color ) {
Color color = (Color) newValue;
int alpha = color.getAlpha();
return String.format( (alpha != 255) ? "#%06x%02x" : "#%06x", color.getRGB() & 0xffffff, alpha );
}
throw new IllegalArgumentException( "property value type '" + newValue.getClass().getName() + "' not supported in references" );
}
enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR, enum ValueType { UNKNOWN, STRING, BOOLEAN, CHARACTER, INTEGER, FLOAT, BORDER, ICON, INSETS, DIMENSION, COLOR,
SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY } SCALEDINTEGER, SCALEDFLOAT, SCALEDINSETS, SCALEDDIMENSION, INSTANCE, CLASS, GRAYFILTER, NULL, LAZY }
private static ValueType[] tempResultValueType = new ValueType[1]; private static ValueType[] tempResultValueType = new ValueType[1];
private static Map<Class<?>, ValueType> javaValueTypes;
static Object parseValue( String key, String value ) { static Object parseValue( String key, String value, Class<?> valueType ) {
return parseValue( key, value, null, v -> v, Collections.emptyList() ); return parseValue( key, value, valueType, null, v -> v, Collections.emptyList() );
} }
static Object parseValue( String key, String value, ValueType[] resultValueType, static Object parseValue( String key, String value, Class<?> javaValueType, ValueType[] resultValueType,
Function<String, String> resolver, List<ClassLoader> addonClassLoaders ) Function<String, String> resolver, List<ClassLoader> addonClassLoaders )
{ {
if( resultValueType == null ) if( resultValueType == null )
@@ -305,70 +327,106 @@ class UIDefaultsLoader
value = value.trim(); value = value.trim();
// null, false, true // null
switch( value ) { if( value.equals( "null" ) ) {
case "null": resultValueType[0] = ValueType.NULL; return null; resultValueType[0] = ValueType.NULL;
case "false": resultValueType[0] = ValueType.BOOLEAN; return false; return null;
case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
}
// check for function "lazy"
// Syntax: lazy(uiKey)
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
resultValueType[0] = ValueType.LAZY;
String uiKey = value.substring( 5, value.length() - 1 ).trim();
return (LazyValue) t -> {
return lazyUIManagerGet( uiKey );
};
} }
ValueType valueType = ValueType.UNKNOWN; ValueType valueType = ValueType.UNKNOWN;
// check whether value type is specified in the value if( javaValueType != null ) {
if( value.startsWith( "#" ) ) if( javaValueTypes == null ) {
valueType = ValueType.COLOR; // create lazy
else if( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) { javaValueTypes = new HashMap<>();
valueType = ValueType.STRING; javaValueTypes.put( String.class, ValueType.STRING );
value = value.substring( 1, value.length() - 1 ); javaValueTypes.put( boolean.class, ValueType.BOOLEAN );
} else if( value.startsWith( TYPE_PREFIX ) ) { javaValueTypes.put( Boolean.class, ValueType.BOOLEAN );
int end = value.indexOf( TYPE_PREFIX_END ); javaValueTypes.put( char.class, ValueType.CHARACTER );
if( end != -1 ) { javaValueTypes.put( Character.class, ValueType.CHARACTER );
try { javaValueTypes.put( int.class, ValueType.INTEGER );
String typeStr = value.substring( TYPE_PREFIX.length(), end ); javaValueTypes.put( Integer.class, ValueType.INTEGER );
valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) ); javaValueTypes.put( float.class, ValueType.FLOAT );
javaValueTypes.put( Float.class, ValueType.FLOAT );
javaValueTypes.put( Border.class, ValueType.BORDER );
javaValueTypes.put( Icon.class, ValueType.ICON );
javaValueTypes.put( Insets.class, ValueType.INSETS );
javaValueTypes.put( Dimension.class, ValueType.DIMENSION );
javaValueTypes.put( Color.class, ValueType.COLOR );
}
// remove type from value // map java value type to parser value type
value = value.substring( end + TYPE_PREFIX_END.length() ); valueType = javaValueTypes.get( javaValueType );
} catch( IllegalArgumentException ex ) { if( valueType == null )
// ignore throw new IllegalArgumentException( "unsupported value type '" + javaValueType.getName() + "'" );
// remove '"' from strings
if( valueType == ValueType.STRING && value.startsWith( "\"" ) && value.endsWith( "\"" ) )
value = value.substring( 1, value.length() - 1 );
} else {
// false, true
switch( value ) {
case "false": resultValueType[0] = ValueType.BOOLEAN; return false;
case "true": resultValueType[0] = ValueType.BOOLEAN; return true;
}
// check for function "lazy"
// Syntax: lazy(uiKey)
if( value.startsWith( "lazy(" ) && value.endsWith( ")" ) ) {
resultValueType[0] = ValueType.LAZY;
String uiKey = value.substring( 5, value.length() - 1 ).trim();
return (LazyValue) t -> {
return lazyUIManagerGet( uiKey );
};
}
// check whether value type is specified in the value
if( value.startsWith( "#" ) )
valueType = ValueType.COLOR;
else if( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) {
valueType = ValueType.STRING;
value = value.substring( 1, value.length() - 1 );
} else if( value.startsWith( TYPE_PREFIX ) ) {
int end = value.indexOf( TYPE_PREFIX_END );
if( end != -1 ) {
try {
String typeStr = value.substring( TYPE_PREFIX.length(), end );
valueType = ValueType.valueOf( typeStr.toUpperCase( Locale.ENGLISH ) );
// remove type from value
value = value.substring( end + TYPE_PREFIX_END.length() );
} catch( IllegalArgumentException ex ) {
// ignore
}
} }
} }
}
// determine value type from key // determine value type from key
if( valueType == ValueType.UNKNOWN ) { if( valueType == ValueType.UNKNOWN ) {
if( key.endsWith( "UI" ) ) if( key.endsWith( "UI" ) )
valueType = ValueType.STRING; valueType = ValueType.STRING;
else if( key.endsWith( "Color" ) || else if( key.endsWith( "Color" ) ||
(key.endsWith( "ground" ) && (key.endsWith( "ground" ) &&
(key.endsWith( ".background" ) || key.endsWith( "Background" ) || (key.endsWith( ".background" ) || key.endsWith( "Background" ) || key.equals( "background" ) ||
key.endsWith( ".foreground" ) || key.endsWith( "Foreground" ))) ) key.endsWith( ".foreground" ) || key.endsWith( "Foreground" ) || key.equals( "foreground" ))) )
valueType = ValueType.COLOR; valueType = ValueType.COLOR;
else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) ) else if( key.endsWith( ".border" ) || key.endsWith( "Border" ) || key.equals( "border" ) )
valueType = ValueType.BORDER; valueType = ValueType.BORDER;
else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) ) else if( key.endsWith( ".icon" ) || key.endsWith( "Icon" ) || key.equals( "icon" ) )
valueType = ValueType.ICON; valueType = ValueType.ICON;
else if( key.endsWith( ".margin" ) || key.endsWith( ".padding" ) || else if( key.endsWith( ".margin" ) || key.equals( "margin" ) ||
key.endsWith( "Margins" ) || key.endsWith( "Insets" ) ) key.endsWith( ".padding" ) || key.equals( "padding" ) ||
valueType = ValueType.INSETS; key.endsWith( "Margins" ) || key.endsWith( "Insets" ) )
else if( key.endsWith( "Size" ) ) valueType = ValueType.INSETS;
valueType = ValueType.DIMENSION; else if( key.endsWith( "Size" ) )
else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) ) valueType = ValueType.DIMENSION;
valueType = ValueType.INTEGER; else if( key.endsWith( "Width" ) || key.endsWith( "Height" ) )
else if( key.endsWith( "Char" ) ) valueType = ValueType.INTEGER;
valueType = ValueType.CHARACTER; else if( key.endsWith( "Char" ) )
else if( key.endsWith( "grayFilter" ) ) valueType = ValueType.CHARACTER;
valueType = ValueType.GRAYFILTER; else if( key.endsWith( "grayFilter" ) )
valueType = ValueType.GRAYFILTER;
}
} }
resultValueType[0] = valueType; resultValueType[0] = valueType;
@@ -376,6 +434,7 @@ class UIDefaultsLoader
// parse value // parse value
switch( valueType ) { switch( valueType ) {
case STRING: return value; case STRING: return value;
case BOOLEAN: return parseBoolean( value );
case CHARACTER: return parseCharacter( value ); case CHARACTER: return parseCharacter( value );
case INTEGER: return parseInteger( value, true ); case INTEGER: return parseInteger( value, true );
case FLOAT: return parseFloat( value, true ); case FLOAT: return parseFloat( value, true );
@@ -868,6 +927,14 @@ class UIDefaultsLoader
return val; return val;
} }
private static Boolean parseBoolean( String value ) {
switch( value ) {
case "false": return false;
case "true": return true;
}
throw new IllegalArgumentException( "invalid boolean '" + value + "'" );
}
private static Character parseCharacter( String value ) { private static Character parseCharacter( String value ) {
if( value.length() != 1 ) if( value.length() != 1 )
throw new IllegalArgumentException( "invalid character '" + value + "'" ); throw new IllegalArgumentException( "invalid character '" + value + "'" );

View File

@@ -39,7 +39,7 @@ public abstract class FlatAbstractIcon
{ {
protected final int width; protected final int width;
protected final int height; protected final int height;
protected final Color color; protected Color color;
public FlatAbstractIcon( int width, int height, Color color ) { public FlatAbstractIcon( int width, int height, Color color ) {
this.width = width; this.width = width;

View File

@@ -21,7 +21,11 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.TableHeaderUI;
import javax.swing.table.JTableHeader;
import com.formdev.flatlaf.ui.FlatTableHeaderUI;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -35,8 +39,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatAscendingSortIcon public class FlatAscendingSortIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) ); protected boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" ); protected Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
public FlatAscendingSortIcon() { public FlatAscendingSortIcon() {
super( 10, 5, null ); super( 10, 5, null );
@@ -44,7 +48,28 @@ public class FlatAscendingSortIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
boolean chevron = this.chevron;
Color sortIconColor = this.sortIconColor;
// Because this icons are always shared for all table headers,
// get icon specific style from FlatTableHeaderUI.
JTableHeader tableHeader = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
if( tableHeader != null ) {
TableHeaderUI ui = tableHeader.getUI();
if( ui instanceof FlatTableHeaderUI ) {
FlatTableHeaderUI fui = (FlatTableHeaderUI) ui;
if( fui.arrowType != null )
chevron = FlatUIUtils.isChevron( fui.arrowType );
if( fui.sortIconColor != null )
sortIconColor = fui.sortIconColor;
}
}
g.setColor( sortIconColor ); g.setColor( sortIconColor );
paintArrow( c, g, chevron );
}
protected void paintArrow( Component c, Graphics2D g, boolean chevron ) {
if( chevron ) { if( chevron ) {
// chevron arrow // chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,4, 5,0, 9,4 ); Path2D path = FlatUIUtils.createPath( false, 1,4, 5,0, 9,4 );

View File

@@ -16,12 +16,14 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -38,6 +40,17 @@ public class FlatCapsLockIcon
super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) ); super( 16, 16, UIManager.getColor( "PasswordField.capsLockIconColor" ) );
} }
/**
* @since 2
*/
public Object applyStyleProperty( String key, Object value ) {
Object oldValue;
switch( key ) {
case "capsLockIconColor": oldValue = color; color = (Color) value; return oldValue;
default: throw new UnknownStyleException( key );
}
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*

View File

@@ -23,10 +23,13 @@ import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.util.Map;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -67,39 +70,39 @@ public class FlatCheckBoxIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final String style = UIManager.getString( "CheckBox.icon.style" ); protected final String style = UIManager.getString( "CheckBox.icon.style" );
public final int focusWidth = getUIInt( "CheckBox.icon.focusWidth", @Styleable public int focusWidth = getUIInt( "CheckBox.icon.focusWidth",
UIManager.getInt( "Component.focusWidth" ), style ); UIManager.getInt( "Component.focusWidth" ), style );
protected final Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusColor", @Styleable protected Color focusColor = FlatUIUtils.getUIColor( "CheckBox.icon.focusColor",
UIManager.getColor( "Component.focusColor" ) ); UIManager.getColor( "Component.focusColor" ) );
protected final int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 ); @Styleable protected int arc = FlatUIUtils.getUIInt( "CheckBox.arc", 2 );
// enabled // enabled
protected final Color borderColor = getUIColor( "CheckBox.icon.borderColor", style ); @Styleable protected Color borderColor = getUIColor( "CheckBox.icon.borderColor", style );
protected final Color background = getUIColor( "CheckBox.icon.background", style ); @Styleable protected Color background = getUIColor( "CheckBox.icon.background", style );
protected final Color selectedBorderColor = getUIColor( "CheckBox.icon.selectedBorderColor", style ); @Styleable protected Color selectedBorderColor = getUIColor( "CheckBox.icon.selectedBorderColor", style );
protected final Color selectedBackground = getUIColor( "CheckBox.icon.selectedBackground", style ); @Styleable protected Color selectedBackground = getUIColor( "CheckBox.icon.selectedBackground", style );
protected final Color checkmarkColor = getUIColor( "CheckBox.icon.checkmarkColor", style ); @Styleable protected Color checkmarkColor = getUIColor( "CheckBox.icon.checkmarkColor", style );
// disabled // disabled
protected final Color disabledBorderColor = getUIColor( "CheckBox.icon.disabledBorderColor", style ); @Styleable protected Color disabledBorderColor = getUIColor( "CheckBox.icon.disabledBorderColor", style );
protected final Color disabledBackground = getUIColor( "CheckBox.icon.disabledBackground", style ); @Styleable protected Color disabledBackground = getUIColor( "CheckBox.icon.disabledBackground", style );
protected final Color disabledCheckmarkColor = getUIColor( "CheckBox.icon.disabledCheckmarkColor", style ); @Styleable protected Color disabledCheckmarkColor = getUIColor( "CheckBox.icon.disabledCheckmarkColor", style );
// focused // focused
protected final Color focusedBorderColor = getUIColor( "CheckBox.icon.focusedBorderColor", style ); @Styleable protected Color focusedBorderColor = getUIColor( "CheckBox.icon.focusedBorderColor", style );
protected final Color focusedBackground = getUIColor( "CheckBox.icon.focusedBackground", style ); @Styleable protected Color focusedBackground = getUIColor( "CheckBox.icon.focusedBackground", style );
protected final Color selectedFocusedBorderColor = getUIColor( "CheckBox.icon.selectedFocusedBorderColor", style ); @Styleable protected Color selectedFocusedBorderColor = getUIColor( "CheckBox.icon.selectedFocusedBorderColor", style );
protected final Color selectedFocusedBackground = getUIColor( "CheckBox.icon.selectedFocusedBackground", style ); @Styleable protected Color selectedFocusedBackground = getUIColor( "CheckBox.icon.selectedFocusedBackground", style );
protected final Color selectedFocusedCheckmarkColor = getUIColor( "CheckBox.icon.selectedFocusedCheckmarkColor", style ); @Styleable protected Color selectedFocusedCheckmarkColor = getUIColor( "CheckBox.icon.selectedFocusedCheckmarkColor", style );
// hover // hover
protected final Color hoverBorderColor = getUIColor( "CheckBox.icon.hoverBorderColor", style ); @Styleable protected Color hoverBorderColor = getUIColor( "CheckBox.icon.hoverBorderColor", style );
protected final Color hoverBackground = getUIColor( "CheckBox.icon.hoverBackground", style ); @Styleable protected Color hoverBackground = getUIColor( "CheckBox.icon.hoverBackground", style );
protected final Color selectedHoverBackground = getUIColor( "CheckBox.icon.selectedHoverBackground", style ); @Styleable protected Color selectedHoverBackground = getUIColor( "CheckBox.icon.selectedHoverBackground", style );
// pressed // pressed
protected final Color pressedBackground = getUIColor( "CheckBox.icon.pressedBackground", style ); @Styleable protected Color pressedBackground = getUIColor( "CheckBox.icon.pressedBackground", style );
protected final Color selectedPressedBackground = getUIColor( "CheckBox.icon.selectedPressedBackground", style ); @Styleable protected Color selectedPressedBackground = getUIColor( "CheckBox.icon.selectedPressedBackground", style );
protected static Color getUIColor( String key, String style ) { protected static Color getUIColor( String key, String style ) {
if( style != null ) { if( style != null ) {
@@ -129,6 +132,20 @@ public class FlatCheckBoxIcon
super( ICON_SIZE, ICON_SIZE, null ); super( ICON_SIZE, ICON_SIZE, null );
} }
/**
* @since 2
*/
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
boolean indeterminate = isIndeterminate( c ); boolean indeterminate = isIndeterminate( c );

View File

@@ -21,9 +21,12 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/** /**
* Icon for {@link javax.swing.JCheckBoxMenuItem}. * Icon for {@link javax.swing.JCheckBoxMenuItem}.
@@ -38,14 +41,28 @@ import javax.swing.UIManager;
public class FlatCheckBoxMenuItemIcon public class FlatCheckBoxMenuItemIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" ); @Styleable protected Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" );
protected final Color disabledCheckmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.disabledCheckmarkColor" ); @Styleable protected Color disabledCheckmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.disabledCheckmarkColor" );
protected final Color selectionForeground = UIManager.getColor( "MenuItem.selectionForeground" ); @Styleable protected Color selectionForeground = UIManager.getColor( "MenuItem.selectionForeground" );
public FlatCheckBoxMenuItemIcon() { public FlatCheckBoxMenuItemIcon() {
super( 15, 15, null ); super( 15, 15, null );
} }
/**
* @since 2
*/
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g2 ) { protected void paintIcon( Component c, Graphics2D g2 ) {
boolean selected = (c instanceof AbstractButton) && ((AbstractButton)c).isSelected(); boolean selected = (c instanceof AbstractButton) && ((AbstractButton)c).isSelected();

View File

@@ -22,9 +22,12 @@ import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.ButtonModel; import javax.swing.ButtonModel;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -40,14 +43,28 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatClearIcon public class FlatClearIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected Color clearIconColor = UIManager.getColor( "SearchField.clearIconColor" ); @Styleable protected Color clearIconColor = UIManager.getColor( "SearchField.clearIconColor" );
protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" ); @Styleable protected Color clearIconHoverColor = UIManager.getColor( "SearchField.clearIconHoverColor" );
protected Color clearIconPressedColor = UIManager.getColor( "SearchField.clearIconPressedColor" ); @Styleable protected Color clearIconPressedColor = UIManager.getColor( "SearchField.clearIconPressedColor" );
public FlatClearIcon() { public FlatClearIcon() {
super( 16, 16, null ); super( 16, 16, null );
} }
/**
* @since 2
*/
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
if( c instanceof AbstractButton ) { if( c instanceof AbstractButton ) {

View File

@@ -17,11 +17,9 @@
package com.formdev.flatlaf.icons; package com.formdev.flatlaf.icons;
import java.awt.BasicStroke; import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -33,18 +31,14 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatDescendingSortIcon public class FlatDescendingSortIcon
extends FlatAbstractIcon extends FlatAscendingSortIcon
{ {
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) );
protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" );
public FlatDescendingSortIcon() { public FlatDescendingSortIcon() {
super( 10, 5, null ); super();
} }
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintArrow( Component c, Graphics2D g, boolean chevron ) {
g.setColor( sortIconColor );
if( chevron ) { if( chevron ) {
// chevron arrow // chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,0, 5,4, 9,0 ); Path2D path = FlatUIUtils.createPath( false, 1,0, 5,4, 9,0 );

View File

@@ -22,8 +22,11 @@ import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -50,29 +53,41 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatHelpButtonIcon public class FlatHelpButtonIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" ); @Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
protected final Color focusColor = UIManager.getColor( "Component.focusColor" ); @Styleable protected Color focusColor = UIManager.getColor( "Component.focusColor" );
protected final float innerFocusWidth = FlatUIUtils.getUIFloat( "HelpButton.innerFocusWidth", FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 ) ); @Styleable protected float innerFocusWidth = FlatUIUtils.getUIFloat( "HelpButton.innerFocusWidth", FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 ) );
protected final int borderWidth = FlatUIUtils.getUIInt( "HelpButton.borderWidth", 1 ); @Styleable protected int borderWidth = FlatUIUtils.getUIInt( "HelpButton.borderWidth", 1 );
protected final Color borderColor = UIManager.getColor( "HelpButton.borderColor" ); @Styleable protected Color borderColor = UIManager.getColor( "HelpButton.borderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "HelpButton.disabledBorderColor" ); @Styleable protected Color disabledBorderColor = UIManager.getColor( "HelpButton.disabledBorderColor" );
protected final Color focusedBorderColor = UIManager.getColor( "HelpButton.focusedBorderColor" ); @Styleable protected Color focusedBorderColor = UIManager.getColor( "HelpButton.focusedBorderColor" );
protected final Color hoverBorderColor = UIManager.getColor( "HelpButton.hoverBorderColor" ); @Styleable protected Color hoverBorderColor = UIManager.getColor( "HelpButton.hoverBorderColor" );
protected final Color background = UIManager.getColor( "HelpButton.background" ); @Styleable protected Color background = UIManager.getColor( "HelpButton.background" );
protected final Color disabledBackground = UIManager.getColor( "HelpButton.disabledBackground" ); @Styleable protected Color disabledBackground = UIManager.getColor( "HelpButton.disabledBackground" );
protected final Color focusedBackground = UIManager.getColor( "HelpButton.focusedBackground" ); @Styleable protected Color focusedBackground = UIManager.getColor( "HelpButton.focusedBackground" );
protected final Color hoverBackground = UIManager.getColor( "HelpButton.hoverBackground" ); @Styleable protected Color hoverBackground = UIManager.getColor( "HelpButton.hoverBackground" );
protected final Color pressedBackground = UIManager.getColor( "HelpButton.pressedBackground" ); @Styleable protected Color pressedBackground = UIManager.getColor( "HelpButton.pressedBackground" );
protected final Color questionMarkColor = UIManager.getColor( "HelpButton.questionMarkColor" ); @Styleable protected Color questionMarkColor = UIManager.getColor( "HelpButton.questionMarkColor" );
protected final Color disabledQuestionMarkColor = UIManager.getColor( "HelpButton.disabledQuestionMarkColor" ); @Styleable protected Color disabledQuestionMarkColor = UIManager.getColor( "HelpButton.disabledQuestionMarkColor" );
protected final int iconSize = 22 + (focusWidth * 2);
public FlatHelpButtonIcon() { public FlatHelpButtonIcon() {
super( 0, 0, null ); super( 0, 0, null );
} }
/**
* @since 2
*/
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g2 ) { protected void paintIcon( Component c, Graphics2D g2 ) {
/* /*
@@ -89,7 +104,7 @@ public class FlatHelpButtonIcon
boolean focused = FlatUIUtils.isPermanentFocusOwner( c ); boolean focused = FlatUIUtils.isPermanentFocusOwner( c );
float xy = 0.5f; float xy = 0.5f;
float wh = iconSize - 1; float wh = iconSize() - 1;
// paint outer focus border // paint outer focus border
if( focused && FlatButtonUI.isFocusPainted( c ) ) { if( focused && FlatButtonUI.isFocusPainted( c ) ) {
@@ -151,11 +166,15 @@ public class FlatHelpButtonIcon
@Override @Override
public int getIconWidth() { public int getIconWidth() {
return scale( iconSize ); return scale( iconSize() );
} }
@Override @Override
public int getIconHeight() { public int getIconHeight() {
return scale( iconSize ); return scale( iconSize() );
}
private int iconSize() {
return 22 + (focusWidth * 2);
} }
} }

View File

@@ -21,9 +21,12 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/** /**
* "arrow" icon for {@link javax.swing.JMenu}. * "arrow" icon for {@link javax.swing.JMenu}.
@@ -39,22 +42,36 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatMenuArrowIcon public class FlatMenuArrowIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) ); @Styleable protected String arrowType = UIManager.getString( "Component.arrowType" );
protected final Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" ); @Styleable protected Color arrowColor = UIManager.getColor( "Menu.icon.arrowColor" );
protected final Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" ); @Styleable protected Color disabledArrowColor = UIManager.getColor( "Menu.icon.disabledArrowColor" );
protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" ); @Styleable protected Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" );
public FlatMenuArrowIcon() { public FlatMenuArrowIcon() {
super( 6, 10, null ); super( 6, 10, null );
} }
/**
* @since 2
*/
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
if( !c.getComponentOrientation().isLeftToRight() ) if( !c.getComponentOrientation().isLeftToRight() )
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. ); g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
g.setColor( getArrowColor( c ) ); g.setColor( getArrowColor( c ) );
if( chevron ) { if( FlatUIUtils.isChevron( arrowType ) ) {
// chevron arrow // chevron arrow
Path2D path = FlatUIUtils.createPath( false, 1,1, 5,5, 1,9 ); Path2D path = FlatUIUtils.createPath( false, 1,1, 5,5, 1,9 );
g.setStroke( new BasicStroke( 1f ) ); g.setStroke( new BasicStroke( 1f ) );

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.icons;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/** /**
* Icon for {@link javax.swing.JRadioButton}. * Icon for {@link javax.swing.JRadioButton}.
@@ -34,7 +35,7 @@ import java.awt.geom.Ellipse2D;
public class FlatRadioButtonIcon public class FlatRadioButtonIcon
extends FlatCheckBoxIcon extends FlatCheckBoxIcon
{ {
protected final int centerDiameter = getUIInt( "RadioButton.icon.centerDiameter", 8, style ); @Styleable protected int centerDiameter = getUIInt( "RadioButton.icon.centerDiameter", 8, style );
@Override @Override
protected void paintFocusBorder( Component c, Graphics2D g ) { protected void paintFocusBorder( Component c, Graphics2D g ) {

View File

@@ -21,8 +21,11 @@ import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Area; import java.awt.geom.Area;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import java.util.Map;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -38,14 +41,28 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatSearchIcon public class FlatSearchIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected Color searchIconColor = UIManager.getColor( "SearchField.searchIconColor" ); @Styleable protected Color searchIconColor = UIManager.getColor( "SearchField.searchIconColor" );
protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" ); @Styleable protected Color searchIconHoverColor = UIManager.getColor( "SearchField.searchIconHoverColor" );
protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" ); @Styleable protected Color searchIconPressedColor = UIManager.getColor( "SearchField.searchIconPressedColor" );
public FlatSearchIcon() { public FlatSearchIcon() {
super( 16, 16, null ); super( 16, 16, null );
} }
/**
* @since 2
*/
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
/* /*

View File

@@ -23,8 +23,11 @@ import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Line2D; import java.awt.geom.Line2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.util.Map;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatButtonUI;
import com.formdev.flatlaf.ui.FlatStylingSupport;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -47,39 +50,53 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
public class FlatTabbedPaneCloseIcon public class FlatTabbedPaneCloseIcon
extends FlatAbstractIcon extends FlatAbstractIcon
{ {
protected final Dimension size = UIManager.getDimension( "TabbedPane.closeSize" ); @Styleable protected Dimension closeSize = UIManager.getDimension( "TabbedPane.closeSize" );
protected final int arc = UIManager.getInt( "TabbedPane.closeArc" ); @Styleable protected int closeArc = UIManager.getInt( "TabbedPane.closeArc" );
protected final float crossPlainSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossPlainSize", 7.5f ); @Styleable protected float closeCrossPlainSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossPlainSize", 7.5f );
protected final float crossFilledSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossFilledSize", crossPlainSize ); @Styleable protected float closeCrossFilledSize = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossFilledSize", closeCrossPlainSize );
protected final float closeCrossLineWidth = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossLineWidth", 1f ); @Styleable protected float closeCrossLineWidth = FlatUIUtils.getUIFloat( "TabbedPane.closeCrossLineWidth", 1f );
protected final Color background = UIManager.getColor( "TabbedPane.closeBackground" ); @Styleable protected Color closeBackground = UIManager.getColor( "TabbedPane.closeBackground" );
protected final Color foreground = UIManager.getColor( "TabbedPane.closeForeground" ); @Styleable protected Color closeForeground = UIManager.getColor( "TabbedPane.closeForeground" );
protected final Color hoverBackground = UIManager.getColor( "TabbedPane.closeHoverBackground" ); @Styleable protected Color closeHoverBackground = UIManager.getColor( "TabbedPane.closeHoverBackground" );
protected final Color hoverForeground = UIManager.getColor( "TabbedPane.closeHoverForeground" ); @Styleable protected Color closeHoverForeground = UIManager.getColor( "TabbedPane.closeHoverForeground" );
protected final Color pressedBackground = UIManager.getColor( "TabbedPane.closePressedBackground" ); @Styleable protected Color closePressedBackground = UIManager.getColor( "TabbedPane.closePressedBackground" );
protected final Color pressedForeground = UIManager.getColor( "TabbedPane.closePressedForeground" ); @Styleable protected Color closePressedForeground = UIManager.getColor( "TabbedPane.closePressedForeground" );
public FlatTabbedPaneCloseIcon() { public FlatTabbedPaneCloseIcon() {
super( 16, 16, null ); super( 16, 16, null );
} }
/**
* @since 2
*/
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
// paint background // paint background
Color bg = FlatButtonUI.buttonStateColor( c, background, null, null, hoverBackground, pressedBackground ); Color bg = FlatButtonUI.buttonStateColor( c, closeBackground, null, null, closeHoverBackground, closePressedBackground );
if( bg != null ) { if( bg != null ) {
g.setColor( FlatUIUtils.deriveColor( bg, c.getBackground() ) ); g.setColor( FlatUIUtils.deriveColor( bg, c.getBackground() ) );
g.fillRoundRect( (width - size.width) / 2, (height - size.height) / 2, g.fillRoundRect( (width - closeSize.width) / 2, (height - closeSize.height) / 2,
size.width, size.height, arc, arc ); closeSize.width, closeSize.height, closeArc, closeArc );
} }
// set cross color // set cross color
Color fg = FlatButtonUI.buttonStateColor( c, foreground, null, null, hoverForeground, pressedForeground ); Color fg = FlatButtonUI.buttonStateColor( c, closeForeground, null, null, closeHoverForeground, closePressedForeground );
g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) ); g.setColor( FlatUIUtils.deriveColor( fg, c.getForeground() ) );
float mx = width / 2; float mx = width / 2;
float my = height / 2; float my = height / 2;
float r = ((bg != null) ? crossFilledSize : crossPlainSize) / 2; float r = ((bg != null) ? closeCrossFilledSize : closeCrossPlainSize) / 2;
// paint cross // paint cross
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD ); Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );

View File

@@ -37,6 +37,8 @@ public class FlatTreeClosedIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconClosedColor );
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/> <polygon fill="#6E6E6E" fill-rule="evenodd" points="1 2 6 2 8 4 15 4 15 13 1 13"/>

View File

@@ -19,7 +19,12 @@ package com.formdev.flatlaf.icons;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.util.function.Function;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.TreeUI;
import com.formdev.flatlaf.ui.FlatTreeUI;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
/** /**
@@ -46,8 +51,12 @@ public class FlatTreeCollapsedIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
setStyleColorFromTreeUI( c, g );
rotate( c, g ); rotate( c, g );
String arrowType = getStyleFromTreeUI( c, ui -> ui.iconArrowType );
boolean chevron = (arrowType != null) ? FlatUIUtils.isChevron( arrowType ) : this.chevron;
if( chevron ) { if( chevron ) {
// chevron arrow // 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 ) ); 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 ) );
@@ -57,8 +66,34 @@ public class FlatTreeCollapsedIcon
} }
} }
void setStyleColorFromTreeUI( Component c, Graphics2D g ) {
setStyleColorFromTreeUI( c, g, ui -> ui.iconCollapsedColor );
}
void rotate( Component c, Graphics2D g ) { void rotate( Component c, Graphics2D g ) {
if( !c.getComponentOrientation().isLeftToRight() ) if( !c.getComponentOrientation().isLeftToRight() )
g.rotate( Math.toRadians( 180 ), width / 2., height / 2. ); g.rotate( Math.toRadians( 180 ), width / 2., height / 2. );
} }
/**
* Because this icons are always shared for all trees,
* get icon specific style from FlatTreeUI.
*/
static <T> T getStyleFromTreeUI( Component c, Function<FlatTreeUI, T> f ) {
JTree tree = (c instanceof JTree)
? (JTree) c
: (JTree) SwingUtilities.getAncestorOfClass( JTree.class, c );
if( tree != null ) {
TreeUI ui = tree.getUI();
if( ui instanceof FlatTreeUI )
return f.apply( (FlatTreeUI) ui );
}
return null;
}
static void setStyleColorFromTreeUI( Component c, Graphics2D g, Function<FlatTreeUI, Color> f ) {
Color color = getStyleFromTreeUI( c, f );
if( color != null )
g.setColor( color );
}
} }

View File

@@ -34,6 +34,11 @@ public class FlatTreeExpandedIcon
super( UIManager.getColor( "Tree.icon.expandedColor" ) ); super( UIManager.getColor( "Tree.icon.expandedColor" ) );
} }
@Override
void setStyleColorFromTreeUI( Component c, Graphics2D g ) {
setStyleColorFromTreeUI( c, g, ui -> ui.iconExpandedColor );
}
@Override @Override
void rotate( Component c, Graphics2D g ) { void rotate( Component c, Graphics2D g ) {
g.rotate( Math.toRadians( 90 ), width / 2., height / 2. ); g.rotate( Math.toRadians( 90 ), width / 2., height / 2. );

View File

@@ -37,6 +37,8 @@ public class FlatTreeLeafIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconLeafColor );
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">

View File

@@ -37,6 +37,8 @@ public class FlatTreeOpenIcon
@Override @Override
protected void paintIcon( Component c, Graphics2D g ) { protected void paintIcon( Component c, Graphics2D g ) {
FlatTreeCollapsedIcon.setStyleColorFromTreeUI( c, g, ui -> ui.iconOpenColor );
/* /*
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd"> <g fill="none" fill-rule="evenodd">

View File

@@ -39,13 +39,13 @@ public class FlatArrowButton
{ {
public static final int DEFAULT_ARROW_WIDTH = 8; public static final int DEFAULT_ARROW_WIDTH = 8;
protected final boolean chevron; protected boolean chevron;
protected final Color foreground; protected Color foreground;
protected final Color disabledForeground; protected Color disabledForeground;
protected final Color hoverForeground; protected Color hoverForeground;
protected final Color hoverBackground; protected Color hoverBackground;
protected final Color pressedForeground; protected Color pressedForeground;
protected final Color pressedBackground; protected Color pressedBackground;
private int arrowWidth = DEFAULT_ARROW_WIDTH; private int arrowWidth = DEFAULT_ARROW_WIDTH;
private float xOffset = 0; private float xOffset = 0;
@@ -58,14 +58,8 @@ public class FlatArrowButton
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground ) Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
{ {
super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE ); super( direction, Color.WHITE, Color.WHITE, Color.WHITE, Color.WHITE );
updateStyle( type, foreground, disabledForeground, hoverForeground, hoverBackground,
this.chevron = FlatUIUtils.isChevron( type ); pressedForeground, pressedBackground );
this.foreground = foreground;
this.disabledForeground = disabledForeground;
this.hoverForeground = hoverForeground;
this.hoverBackground = hoverBackground;
this.pressedForeground = pressedForeground;
this.pressedBackground = pressedBackground;
setOpaque( false ); setOpaque( false );
setBorder( null ); setBorder( null );
@@ -101,6 +95,21 @@ public class FlatArrowButton
} }
} }
/**
* @since 2
*/
public void updateStyle( String type, Color foreground, Color disabledForeground,
Color hoverForeground, Color hoverBackground, Color pressedForeground, Color pressedBackground )
{
this.chevron = FlatUIUtils.isChevron( type );
this.foreground = foreground;
this.disabledForeground = disabledForeground;
this.hoverForeground = hoverForeground;
this.hoverBackground = hoverBackground;
this.pressedForeground = pressedForeground;
this.pressedBackground = pressedBackground;
}
public int getArrowWidth() { public int getArrowWidth() {
return arrowWidth; return arrowWidth;
} }

View File

@@ -23,6 +23,7 @@ import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Paint; import java.awt.Paint;
import java.util.Map;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@@ -31,6 +32,8 @@ import javax.swing.JViewport;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicBorders; import javax.swing.plaf.basic.BasicBorders;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
import com.formdev.flatlaf.util.DerivedColor; import com.formdev.flatlaf.util.DerivedColor;
/** /**
@@ -61,20 +64,37 @@ import com.formdev.flatlaf.util.DerivedColor;
*/ */
public class FlatBorder public class FlatBorder
extends BasicBorders.MarginBorder extends BasicBorders.MarginBorder
implements StyleableBorder
{ {
protected final int focusWidth = UIManager.getInt( "Component.focusWidth" ); @Styleable protected int focusWidth = UIManager.getInt( "Component.focusWidth" );
protected final float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 ); @Styleable protected float innerFocusWidth = FlatUIUtils.getUIFloat( "Component.innerFocusWidth", 0 );
protected final float innerOutlineWidth = FlatUIUtils.getUIFloat( "Component.innerOutlineWidth", 0 ); @Styleable protected float innerOutlineWidth = FlatUIUtils.getUIFloat( "Component.innerOutlineWidth", 0 );
protected final Color focusColor = UIManager.getColor( "Component.focusColor" ); @Styleable protected Color focusColor = UIManager.getColor( "Component.focusColor" );
protected final Color borderColor = UIManager.getColor( "Component.borderColor" ); @Styleable protected Color borderColor = UIManager.getColor( "Component.borderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" ); @Styleable protected Color disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
protected final Color focusedBorderColor = UIManager.getColor( "Component.focusedBorderColor" ); @Styleable protected Color focusedBorderColor = UIManager.getColor( "Component.focusedBorderColor" );
protected final Color errorBorderColor = UIManager.getColor( "Component.error.borderColor" ); @Styleable(dot=true) protected Color errorBorderColor = UIManager.getColor( "Component.error.borderColor" );
protected final Color errorFocusedBorderColor = UIManager.getColor( "Component.error.focusedBorderColor" ); @Styleable(dot=true) protected Color errorFocusedBorderColor = UIManager.getColor( "Component.error.focusedBorderColor" );
protected final Color warningBorderColor = UIManager.getColor( "Component.warning.borderColor" ); @Styleable(dot=true) protected Color warningBorderColor = UIManager.getColor( "Component.warning.borderColor" );
protected final Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" ); @Styleable(dot=true) protected Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" );
protected final Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" ); @Styleable(dot=true) protected Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" );
/**
* @since 2
*/
@Override
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {

View File

@@ -26,6 +26,7 @@ import java.awt.Paint;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -40,16 +41,16 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Button.default.borderColor Color * @uiDefault Button.default.borderColor Color
* @uiDefault Button.default.startBorderColor Color optional; if set, a gradient paint is used and Button.default.borderColor is ignored * @uiDefault Button.default.startBorderColor Color optional; if set, a gradient paint is used and Button.default.borderColor is ignored
* @uiDefault Button.default.endBorderColor Color optional; if set, a gradient paint is used * @uiDefault Button.default.endBorderColor Color optional; if set, a gradient paint is used
* @uiDefault Button.default.hoverBorderColor Color optional
* @uiDefault Button.default.focusedBorderColor Color * @uiDefault Button.default.focusedBorderColor Color
* @uiDefault Button.default.focusColor Color * @uiDefault Button.default.focusColor Color
* @uiDefault Button.default.hoverBorderColor Color optional
* @uiDefault Button.toolbar.focusColor Color optional; defaults to Component.focusColor * @uiDefault Button.toolbar.focusColor Color optional; defaults to Component.focusColor
* @uiDefault Button.borderWidth int * @uiDefault Button.borderWidth int
* @uiDefault Button.default.borderWidth int * @uiDefault Button.default.borderWidth int
* @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth * @uiDefault Button.innerFocusWidth int or float optional; defaults to Component.innerFocusWidth
* @uiDefault Button.toolbar.margin Insets * @uiDefault Button.toolbar.margin Insets
* @uiDefault Button.toolbar.spacingInsets Insets * @uiDefault Button.toolbar.spacingInsets Insets
* @uiDefault Button.toolbar.focusWidth int or float optional; default is 1 * @uiDefault Button.toolbar.focusWidth int or float optional; default is 1.5
* @uiDefault Button.arc int * @uiDefault Button.arc int
* *
* @author Karl Tauber * @author Karl Tauber
@@ -57,26 +58,31 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatButtonBorder public class FlatButtonBorder
extends FlatBorder extends FlatBorder
{ {
protected final Color borderColor = FlatUIUtils.getUIColor( "Button.startBorderColor", "Button.borderColor" ); @Styleable protected Color borderColor = FlatUIUtils.getUIColor( "Button.startBorderColor", "Button.borderColor" );
protected final Color endBorderColor = UIManager.getColor( "Button.endBorderColor" ); protected Color endBorderColor = UIManager.getColor( "Button.endBorderColor" );
protected final Color disabledBorderColor = UIManager.getColor( "Button.disabledBorderColor" ); @Styleable protected Color disabledBorderColor = UIManager.getColor( "Button.disabledBorderColor" );
protected final Color focusedBorderColor = UIManager.getColor( "Button.focusedBorderColor" ); @Styleable protected Color focusedBorderColor = UIManager.getColor( "Button.focusedBorderColor" );
protected final Color hoverBorderColor = UIManager.getColor( "Button.hoverBorderColor" ); @Styleable protected Color hoverBorderColor = UIManager.getColor( "Button.hoverBorderColor" );
protected final Color defaultBorderColor = FlatUIUtils.getUIColor( "Button.default.startBorderColor", "Button.default.borderColor" );
protected final Color defaultEndBorderColor = UIManager.getColor( "Button.default.endBorderColor" ); @Styleable(dot=true) protected Color defaultBorderColor = FlatUIUtils.getUIColor( "Button.default.startBorderColor", "Button.default.borderColor" );
protected final Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" ); protected Color defaultEndBorderColor = UIManager.getColor( "Button.default.endBorderColor" );
protected final Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" ); @Styleable(dot=true) protected Color defaultFocusedBorderColor = UIManager.getColor( "Button.default.focusedBorderColor" );
protected final Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" ); @Styleable(dot=true) protected Color defaultFocusColor = UIManager.getColor( "Button.default.focusColor" );
@Styleable(dot=true) protected Color defaultHoverBorderColor = UIManager.getColor( "Button.default.hoverBorderColor" );
/** @since 1.4 */ /** @since 1.4 */
protected final Color toolbarFocusColor = UIManager.getColor( "Button.toolbar.focusColor" ); @Styleable(dot=true) protected Color toolbarFocusColor = UIManager.getColor( "Button.toolbar.focusColor" );
protected final int borderWidth = UIManager.getInt( "Button.borderWidth" );
protected final int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" ); @Styleable protected int borderWidth = UIManager.getInt( "Button.borderWidth" );
protected final float buttonInnerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth ); @Styleable(dot=true) protected int defaultBorderWidth = UIManager.getInt( "Button.default.borderWidth" );
protected final Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" ); @Styleable(dot=true) protected Insets toolbarMargin = UIManager.getInsets( "Button.toolbar.margin" );
protected final Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" ); @Styleable(dot=true) protected Insets toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
/** @since 1.4 */ /** @since 1.4 */
protected final float toolbarFocusWidth = FlatUIUtils.getUIFloat( "Button.toolbar.focusWidth", 1.5f ); @Styleable(dot=true) protected float toolbarFocusWidth = FlatUIUtils.getUIFloat( "Button.toolbar.focusWidth", 1.5f );
protected final int arc = UIManager.getInt( "Button.arc" ); @Styleable protected int arc = UIManager.getInt( "Button.arc" );
public FlatButtonBorder() {
innerFocusWidth = FlatUIUtils.getUIFloat( "Button.innerFocusWidth", innerFocusWidth );
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
@@ -174,11 +180,6 @@ public class FlatButtonBorder
return FlatToggleButtonUI.isTabButton( c ) ? 0 : super.getFocusWidth( c ); return FlatToggleButtonUI.isTabButton( c ) ? 0 : super.getFocusWidth( c );
} }
@Override
protected float getInnerFocusWidth( Component c ) {
return buttonInnerFocusWidth;
}
@Override @Override
protected int getBorderWidth( Component c ) { protected int getBorderWidth( Component c ) {
return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : borderWidth; return FlatButtonUI.isDefaultButton( c ) ? defaultBorderWidth : borderWidth;

View File

@@ -30,7 +30,9 @@ import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.ButtonModel; import javax.swing.ButtonModel;
import javax.swing.Icon; import javax.swing.Icon;
@@ -45,6 +47,10 @@ import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener; import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicButtonUI; import javax.swing.plaf.basic.BasicButtonUI;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatHelpButtonIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -94,8 +100,9 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatButtonUI public class FlatButtonUI
extends BasicButtonUI extends BasicButtonUI
implements StyleableUI
{ {
protected int minimumWidth; @Styleable protected int minimumWidth;
protected int iconTextGap; protected int iconTextGap;
protected Color background; protected Color background;
@@ -103,39 +110,57 @@ public class FlatButtonUI
protected Color startBackground; protected Color startBackground;
protected Color endBackground; protected Color endBackground;
protected Color focusedBackground; @Styleable protected Color focusedBackground;
protected Color hoverBackground; @Styleable protected Color hoverBackground;
protected Color pressedBackground; @Styleable protected Color pressedBackground;
protected Color selectedBackground; @Styleable protected Color selectedBackground;
protected Color selectedForeground; @Styleable protected Color selectedForeground;
protected Color disabledBackground; @Styleable protected Color disabledBackground;
protected Color disabledText; @Styleable protected Color disabledText;
protected Color disabledSelectedBackground; @Styleable protected Color disabledSelectedBackground;
protected Color defaultBackground; @Styleable(dot=true) protected Color defaultBackground;
protected Color defaultEndBackground; protected Color defaultEndBackground;
protected Color defaultForeground; @Styleable(dot=true) protected Color defaultForeground;
protected Color defaultFocusedBackground; @Styleable(dot=true) protected Color defaultFocusedBackground;
protected Color defaultHoverBackground; @Styleable(dot=true) protected Color defaultHoverBackground;
protected Color defaultPressedBackground; @Styleable(dot=true) protected Color defaultPressedBackground;
protected boolean defaultBoldText; @Styleable(dot=true) protected boolean defaultBoldText;
protected int shadowWidth; @Styleable protected boolean paintShadow;
protected Color shadowColor; @Styleable protected int shadowWidth;
protected Color defaultShadowColor; @Styleable protected Color shadowColor;
@Styleable(dot=true) protected Color defaultShadowColor;
protected Insets toolbarSpacingInsets; @Styleable(dot=true) protected Insets toolbarSpacingInsets;
protected Color toolbarHoverBackground; @Styleable(dot=true) protected Color toolbarHoverBackground;
protected Color toolbarPressedBackground; @Styleable(dot=true) protected Color toolbarPressedBackground;
protected Color toolbarSelectedBackground; @Styleable(dot=true) protected Color toolbarSelectedBackground;
private Icon helpButtonIcon; private Icon helpButtonIcon;
private Insets defaultMargin; private Insets defaultMargin;
private final boolean shared;
private boolean helpButtonIconShared = true;
private boolean defaults_initialized = false; private boolean defaults_initialized = false;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatButtonUI.class, FlatButtonUI::new ); return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatButtonUI.class, () -> new FlatButtonUI( true ) )
: new FlatButtonUI( false );
}
protected FlatButtonUI( boolean shared ) {
this.shared = shared;
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( (AbstractButton) c, FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -162,16 +187,6 @@ public class FlatButtonUI
disabledText = UIManager.getColor( prefix + "disabledText" ); disabledText = UIManager.getColor( prefix + "disabledText" );
disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" ); disabledSelectedBackground = UIManager.getColor( prefix + "disabledSelectedBackground" );
if( UIManager.getBoolean( "Button.paintShadow" ) ) {
shadowWidth = FlatUIUtils.getUIInt( "Button.shadowWidth", 2 );
shadowColor = UIManager.getColor( "Button.shadowColor" );
defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" );
} else {
shadowWidth = 0;
shadowColor = null;
defaultShadowColor = null;
}
defaultBackground = FlatUIUtils.getUIColor( "Button.default.startBackground", "Button.default.background" ); defaultBackground = FlatUIUtils.getUIColor( "Button.default.startBackground", "Button.default.background" );
defaultEndBackground = UIManager.getColor( "Button.default.endBackground" ); defaultEndBackground = UIManager.getColor( "Button.default.endBackground" );
defaultForeground = UIManager.getColor( "Button.default.foreground" ); defaultForeground = UIManager.getColor( "Button.default.foreground" );
@@ -180,6 +195,11 @@ public class FlatButtonUI
defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" ); defaultPressedBackground = UIManager.getColor( "Button.default.pressedBackground" );
defaultBoldText = UIManager.getBoolean( "Button.default.boldText" ); defaultBoldText = UIManager.getBoolean( "Button.default.boldText" );
paintShadow = UIManager.getBoolean( "Button.paintShadow" );
shadowWidth = FlatUIUtils.getUIInt( "Button.shadowWidth", 2 );
shadowColor = UIManager.getColor( "Button.shadowColor" );
defaultShadowColor = UIManager.getColor( "Button.default.shadowColor" );
toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" ); toolbarSpacingInsets = UIManager.getInsets( "Button.toolbar.spacingInsets" );
toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" ); toolbarHoverBackground = UIManager.getColor( prefix + "toolbar.hoverBackground" );
toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" ); toolbarPressedBackground = UIManager.getColor( prefix + "toolbar.pressedBackground" );
@@ -188,6 +208,7 @@ public class FlatButtonUI
helpButtonIcon = UIManager.getIcon( "HelpButton.icon" ); helpButtonIcon = UIManager.getIcon( "HelpButton.icon" );
defaultMargin = UIManager.getInsets( prefix + "margin" ); defaultMargin = UIManager.getInsets( prefix + "margin" );
helpButtonIconShared = true;
defaults_initialized = true; defaults_initialized = true;
} }
@@ -207,6 +228,9 @@ public class FlatButtonUI
protected void uninstallDefaults( AbstractButton b ) { protected void uninstallDefaults( AbstractButton b ) {
super.uninstallDefaults( b ); super.uninstallDefaults( b );
oldStyleValues = null;
borderShared = null;
MigLayoutVisualPadding.uninstall( b ); MigLayoutVisualPadding.uninstall( b );
defaults_initialized = false; defaults_initialized = false;
} }
@@ -228,9 +252,62 @@ public class FlatButtonUI
b.revalidate(); b.revalidate();
b.repaint(); b.repaint();
break; break;
case STYLE:
Object style = e.getNewValue();
if( style != null && shared ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
b.updateUI();
} else
applyStyle( b, style );
b.revalidate();
b.repaint();
break;
} }
} }
/**
* @since 2
*/
protected void applyStyle( AbstractButton b, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
(key, value) -> applyStyleProperty( b, key, value ) );
}
/**
* @since 2
*/
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
if( key.startsWith( "help." ) ) {
if( !(helpButtonIcon instanceof FlatHelpButtonIcon) )
return new UnknownStyleException( key );
if( helpButtonIconShared ) {
helpButtonIcon = FlatStylingSupport.cloneIcon( helpButtonIcon );
helpButtonIconShared = false;
}
key = key.substring( "help.".length() );
return ((FlatHelpButtonIcon)helpButtonIcon).applyStyleProperty( key, value );
}
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, b, borderShared );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this, c.getBorder() );
if( helpButtonIcon instanceof FlatHelpButtonIcon )
FlatStylingSupport.putAllPrefixKey( infos, "help.", ((FlatHelpButtonIcon)helpButtonIcon).getStyleableInfos() );
return infos;
}
static boolean isContentAreaFilled( Component c ) { static boolean isContentAreaFilled( Component c ) {
return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled(); return !(c instanceof AbstractButton) || ((AbstractButton)c).isContentAreaFilled();
} }
@@ -339,7 +416,8 @@ public class FlatButtonUI
// paint shadow // paint shadow
Color shadowColor = def ? defaultShadowColor : this.shadowColor; Color shadowColor = def ? defaultShadowColor : this.shadowColor;
if( shadowColor != null && shadowWidth > 0 && focusWidth > 0 && c.isEnabled() && if( paintShadow &&
shadowColor != null && shadowWidth > 0 && focusWidth > 0 && c.isEnabled() &&
!isToolBarButton && !isBorderlessButton( c ) && !isToolBarButton && !isBorderlessButton( c ) &&
!(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) ) !(isFocusPainted( c ) && FlatUIUtils.isPermanentFocusOwner( c )) )
{ {

View File

@@ -18,11 +18,15 @@ package com.formdev.flatlaf.ui;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI; import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JCheckBoxMenuItem}. * Provides the Flat LaF UI delegate for {@link javax.swing.JCheckBoxMenuItem}.
@@ -54,13 +58,22 @@ import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;
*/ */
public class FlatCheckBoxMenuItemUI public class FlatCheckBoxMenuItemUI
extends BasicCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI
implements StyleableUI
{ {
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatCheckBoxMenuItemUI(); return new FlatCheckBoxMenuItemUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( menuItem ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -75,12 +88,46 @@ public class FlatCheckBoxMenuItemUI
super.uninstallDefaults(); super.uninstallDefaults();
renderer = null; renderer = null;
oldStyleValues = null;
} }
protected FlatMenuItemRenderer createRenderer() { protected FlatMenuItemRenderer createRenderer() {
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter ); return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
} }
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) );
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
return FlatMenuItemUI.applyStyleProperty( this, menuItem, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatMenuItemUI.getStyleableInfos( renderer );
}
@Override @Override
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) { protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
return renderer.getPreferredMenuItemSize(); return renderer.getPreferredMenuItemSize();

View File

@@ -43,7 +43,16 @@ public class FlatCheckBoxUI
extends FlatRadioButtonUI extends FlatRadioButtonUI
{ {
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, FlatCheckBoxUI::new ); return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatCheckBoxUI.class, () -> new FlatCheckBoxUI( true ) )
: new FlatCheckBoxUI( false );
}
/**
* @since 2
*/
protected FlatCheckBoxUI( boolean shared ) {
super( shared );
} }
@Override @Override

View File

@@ -41,6 +41,9 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.CellRendererPane; import javax.swing.CellRendererPane;
@@ -67,6 +70,8 @@ import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup; import javax.swing.plaf.basic.ComboPopup;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
/** /**
@@ -108,29 +113,30 @@ import com.formdev.flatlaf.util.SystemInfo;
*/ */
public class FlatComboBoxUI public class FlatComboBoxUI
extends BasicComboBoxUI extends BasicComboBoxUI
implements StyleableUI
{ {
protected int minimumWidth; @Styleable protected int minimumWidth;
protected int editorColumns; @Styleable protected int editorColumns;
protected String buttonStyle; @Styleable protected String buttonStyle;
protected String arrowType; @Styleable protected String arrowType;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color borderColor; @Styleable protected Color borderColor;
protected Color disabledBorderColor; @Styleable protected Color disabledBorderColor;
protected Color editableBackground; @Styleable protected Color editableBackground;
protected Color focusedBackground; @Styleable protected Color focusedBackground;
protected Color disabledBackground; @Styleable protected Color disabledBackground;
protected Color disabledForeground; @Styleable protected Color disabledForeground;
protected Color buttonBackground; @Styleable protected Color buttonBackground;
protected Color buttonEditableBackground; @Styleable protected Color buttonEditableBackground;
protected Color buttonFocusedBackground; @Styleable protected Color buttonFocusedBackground;
protected Color buttonArrowColor; @Styleable protected Color buttonArrowColor;
protected Color buttonDisabledArrowColor; @Styleable protected Color buttonDisabledArrowColor;
protected Color buttonHoverArrowColor; @Styleable protected Color buttonHoverArrowColor;
protected Color buttonPressedArrowColor; @Styleable protected Color buttonPressedArrowColor;
protected Color popupBackground; @Styleable protected Color popupBackground;
private MouseListener hoverListener; private MouseListener hoverListener;
protected boolean hover; protected boolean hover;
@@ -138,10 +144,20 @@ public class FlatComboBoxUI
private CellPaddingBorder paddingBorder; private CellPaddingBorder paddingBorder;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatComboBoxUI(); return new FlatComboBoxUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( comboBox ) );
}
@Override @Override
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
@@ -250,6 +266,9 @@ public class FlatComboBoxUI
paddingBorder.uninstall(); paddingBorder.uninstall();
oldStyleValues = null;
borderShared = null;
MigLayoutVisualPadding.uninstall( comboBox ); MigLayoutVisualPadding.uninstall( comboBox );
} }
@@ -328,6 +347,11 @@ public class FlatComboBoxUI
comboBox.repaint(); comboBox.repaint();
else if( FlatClientProperties.MINIMUM_WIDTH.equals( propertyName ) ) else if( FlatClientProperties.MINIMUM_WIDTH.equals( propertyName ) )
comboBox.revalidate(); comboBox.revalidate();
else if( FlatClientProperties.STYLE.equals( propertyName ) ) {
applyStyle( e.getNewValue() );
comboBox.revalidate();
comboBox.repaint();
}
}; };
} }
@@ -414,6 +438,55 @@ public class FlatComboBoxUI
return new FlatComboBoxButton(); return new FlatComboBoxButton();
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
Insets oldPadding = padding;
int oldEditorColumns = editorColumns;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
if( !padding.equals( oldPadding ) ) {
paddingBorder.padding = padding;
updateEditorPadding();
}
if( arrowButton instanceof FlatComboBoxButton )
((FlatComboBoxButton)arrowButton).updateStyle();
if( popup instanceof FlatComboPopup )
((FlatComboPopup)popup).updateStyle();
if( editorColumns != oldEditorColumns && editor instanceof JTextField )
((JTextField)editor).setColumns( editorColumns );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
// BasicComboBoxUI
if( key.equals( "padding" ) ) {
Object oldValue = padding;
padding = (Insets) value;
return oldValue;
}
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, comboBox, borderShared );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = new LinkedHashMap<>();
infos.put( "padding", Insets.class );
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
FlatStylingSupport.collectStyleableInfos( comboBox.getBorder(), infos );
return infos;
}
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
float focusWidth = FlatUIUtils.getBorderFocusWidth( c ); float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
@@ -612,6 +685,11 @@ public class FlatComboBoxUI
hoverForeground, hoverBackground, pressedForeground, pressedBackground ); hoverForeground, hoverBackground, pressedForeground, pressedBackground );
} }
protected void updateStyle() {
updateStyle( arrowType, buttonArrowColor, buttonDisabledArrowColor,
buttonHoverArrowColor, null, buttonPressedArrowColor, null );
}
@Override @Override
protected boolean isHover() { protected boolean isHover() {
return super.isHover() || (!comboBox.isEditable() ? hover : false); return super.isHover() || (!comboBox.isEditable() ? hover : false);
@@ -708,6 +786,10 @@ public class FlatComboBoxUI
super.configureList(); super.configureList();
list.setCellRenderer( new PopupListCellRenderer() ); list.setCellRenderer( new PopupListCellRenderer() );
updateStyle();
}
void updateStyle() {
if( popupBackground != null ) if( popupBackground != null )
list.setBackground( popupBackground ); list.setBackground( popupBackground );
} }
@@ -788,7 +870,7 @@ public class FlatComboBoxUI
private static class CellPaddingBorder private static class CellPaddingBorder
extends AbstractBorder extends AbstractBorder
{ {
private final Insets padding; private Insets padding;
private JComponent rendererComponent; private JComponent rendererComponent;
private Border rendererBorder; private Border rendererBorder;

View File

@@ -24,6 +24,9 @@ import java.awt.Image;
import java.awt.Insets; import java.awt.Insets;
import java.awt.RadialGradientPaint; import java.awt.RadialGradientPaint;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.Map;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -40,14 +43,17 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatDropShadowBorder public class FlatDropShadowBorder
extends FlatEmptyBorder extends FlatEmptyBorder
implements StyleableBorder
{ {
private final Color shadowColor; @Styleable protected Color shadowColor;
private final Insets shadowInsets; @Styleable protected Insets shadowInsets;
private final float shadowOpacity; @Styleable protected float shadowOpacity;
private final int shadowSize; private int shadowSize;
private Image shadowImage; private Image shadowImage;
private Color lastShadowColor; private Color lastShadowColor;
private float lastShadowOpacity;
private int lastShadowSize;
private double lastSystemScaleFactor; private double lastSystemScaleFactor;
private float lastUserScaleFactor; private float lastUserScaleFactor;
@@ -64,17 +70,47 @@ public class FlatDropShadowBorder
} }
public FlatDropShadowBorder( Color shadowColor, Insets shadowInsets, float shadowOpacity ) { public FlatDropShadowBorder( Color shadowColor, Insets shadowInsets, float shadowOpacity ) {
super( Math.max( shadowInsets.top, 0 ), Math.max( shadowInsets.left, 0 ), super( nonNegativeInsets( shadowInsets ) );
Math.max( shadowInsets.bottom, 0 ), Math.max( shadowInsets.right, 0 ) );
this.shadowColor = shadowColor; this.shadowColor = shadowColor;
this.shadowInsets = shadowInsets; this.shadowInsets = shadowInsets;
this.shadowOpacity = shadowOpacity; this.shadowOpacity = shadowOpacity;
shadowSize = Math.max( shadowSize = maxInset( shadowInsets );
}
private static Insets nonNegativeInsets( Insets shadowInsets ) {
return new Insets( Math.max( shadowInsets.top, 0 ), Math.max( shadowInsets.left, 0 ),
Math.max( shadowInsets.bottom, 0 ), Math.max( shadowInsets.right, 0 ) );
}
private int maxInset( Insets shadowInsets ) {
return Math.max(
Math.max( shadowInsets.left, shadowInsets.right ), Math.max( shadowInsets.left, shadowInsets.right ),
Math.max( shadowInsets.top, shadowInsets.bottom ) ); Math.max( shadowInsets.top, shadowInsets.bottom ) );
} }
/**
* @since 2
*/
@Override
public Object applyStyleProperty( String key, Object value ) {
Object oldValue = FlatStylingSupport.applyToAnnotatedObject( this, key, value );
if( key.equals( "shadowInsets" ) ) {
applyStyleProperty( nonNegativeInsets( shadowInsets ) );
shadowSize = maxInset( shadowInsets );
}
return oldValue;
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
if( shadowSize <= 0 ) if( shadowSize <= 0 )
@@ -91,12 +127,16 @@ public class FlatDropShadowBorder
float userScaleFactor = UIScale.getUserScaleFactor(); float userScaleFactor = UIScale.getUserScaleFactor();
if( shadowImage == null || if( shadowImage == null ||
!shadowColor.equals( lastShadowColor ) || !shadowColor.equals( lastShadowColor ) ||
lastShadowOpacity != shadowOpacity ||
lastShadowSize != shadowSize ||
lastSystemScaleFactor != scaleFactor || lastSystemScaleFactor != scaleFactor ||
lastUserScaleFactor != userScaleFactor ) lastUserScaleFactor != userScaleFactor )
{ {
shadowImage = createShadowImage( shadowColor, shadowSize, shadowOpacity, shadowImage = createShadowImage( shadowColor, shadowSize, shadowOpacity,
(float) (scaleFactor * userScaleFactor) ); (float) (scaleFactor * userScaleFactor) );
lastShadowColor = shadowColor; lastShadowColor = shadowColor;
lastShadowOpacity = shadowOpacity;
lastShadowSize = shadowSize;
lastSystemScaleFactor = scaleFactor; lastSystemScaleFactor = scaleFactor;
lastUserScaleFactor = userScaleFactor; lastUserScaleFactor = userScaleFactor;
} }

View File

@@ -24,6 +24,8 @@ import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.function.Consumer;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JEditorPane; import javax.swing.JEditorPane;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -31,6 +33,8 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicEditorPaneUI; import javax.swing.plaf.basic.BasicEditorPaneUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
@@ -61,20 +65,35 @@ import com.formdev.flatlaf.util.HiDPIUtils;
*/ */
public class FlatEditorPaneUI public class FlatEditorPaneUI
extends BasicEditorPaneUI extends BasicEditorPaneUI
implements StyleableUI
{ {
protected int minimumWidth; @Styleable protected int minimumWidth;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color focusedBackground; private Color background;
@Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground;
@Styleable protected Color focusedBackground;
private Color oldDisabledBackground;
private Color oldInactiveBackground;
private Insets defaultMargin; private Insets defaultMargin;
private Object oldHonorDisplayProperties; private Object oldHonorDisplayProperties;
private FocusListener focusListener; private FocusListener focusListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatEditorPaneUI(); return new FlatEditorPaneUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -82,6 +101,9 @@ public class FlatEditorPaneUI
String prefix = getPropertyPrefix(); String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( prefix + ".background" );
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
defaultMargin = UIManager.getInsets( prefix + ".margin" ); defaultMargin = UIManager.getInsets( prefix + ".margin" );
@@ -95,8 +117,16 @@ public class FlatEditorPaneUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
background = null;
disabledBackground = null;
inactiveBackground = null;
focusedBackground = null; focusedBackground = null;
oldDisabledBackground = null;
oldInactiveBackground = null;
oldStyleValues = null;
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties ); getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
} }
@@ -119,18 +149,62 @@ public class FlatEditorPaneUI
@Override @Override
protected void propertyChange( PropertyChangeEvent e ) { protected void propertyChange( PropertyChangeEvent e ) {
// invoke updateBackground() before super.propertyChange()
String propertyName = e.getPropertyName();
if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
updateBackground();
super.propertyChange( e ); super.propertyChange( e );
propertyChange( getComponent(), e ); propertyChange( getComponent(), e, this::applyStyle );
} }
static void propertyChange( JTextComponent c, PropertyChangeEvent e ) { static void propertyChange( JTextComponent c, PropertyChangeEvent e, Consumer<Object> applyStyle ) {
switch( e.getPropertyName() ) { switch( e.getPropertyName() ) {
case FlatClientProperties.MINIMUM_WIDTH: case FlatClientProperties.MINIMUM_WIDTH:
c.revalidate(); c.revalidate();
break; break;
case FlatClientProperties.STYLE:
applyStyle.accept( e.getNewValue() );
c.revalidate();
c.repaint();
break;
} }
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldDisabledBackground = disabledBackground;
oldInactiveBackground = inactiveBackground;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
updateBackground();
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, getComponent(), key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
private void updateBackground() {
FlatTextFieldUI.updateBackground( getComponent(), background,
disabledBackground, inactiveBackground,
oldDisabledBackground, oldInactiveBackground );
}
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth, defaultMargin ); return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth, defaultMargin );

View File

@@ -50,6 +50,12 @@ public class FlatEmptyBorder
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
return scaleInsets( c, insets, top, left, bottom, right );
}
protected static Insets scaleInsets( Component c, Insets insets,
int top, int left, int bottom, int right )
{
boolean leftToRight = left == right || c.getComponentOrientation().isLeftToRight(); boolean leftToRight = left == right || c.getComponentOrientation().isLeftToRight();
insets.left = scale( leftToRight ? left : right ); insets.left = scale( leftToRight ? left : right );
insets.top = scale( top ); insets.top = scale( top );
@@ -61,4 +67,13 @@ public class FlatEmptyBorder
public Insets getUnscaledBorderInsets() { public Insets getUnscaledBorderInsets() {
return super.getBorderInsets(); return super.getBorderInsets();
} }
public Object applyStyleProperty( Insets insets ) {
Insets oldInsets = getUnscaledBorderInsets();
top = insets.top;
left = insets.left;
bottom = insets.bottom;
right = insets.right;
return oldInsets;
}
} }

View File

@@ -24,6 +24,10 @@ import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JInternalFrame; import javax.swing.JInternalFrame;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
@@ -31,6 +35,9 @@ import javax.swing.UIManager;
import javax.swing.event.MouseInputAdapter; import javax.swing.event.MouseInputAdapter;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicInternalFrameUI; import javax.swing.plaf.basic.BasicInternalFrameUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JInternalFrame}. * Provides the Flat LaF UI delegate for {@link javax.swing.JInternalFrame}.
@@ -86,9 +93,13 @@ import javax.swing.plaf.basic.BasicInternalFrameUI;
*/ */
public class FlatInternalFrameUI public class FlatInternalFrameUI
extends BasicInternalFrameUI extends BasicInternalFrameUI
implements StyleableUI
{ {
protected FlatWindowResizer windowResizer; protected FlatWindowResizer windowResizer;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatInternalFrameUI( (JInternalFrame) c ); return new FlatInternalFrameUI( (JInternalFrame) c );
} }
@@ -104,6 +115,8 @@ public class FlatInternalFrameUI
LookAndFeel.installProperty( frame, "opaque", false ); LookAndFeel.installProperty( frame, "opaque", false );
windowResizer = createWindowResizer(); windowResizer = createWindowResizer();
applyStyle( FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -114,6 +127,9 @@ public class FlatInternalFrameUI
windowResizer.uninstall(); windowResizer.uninstall();
windowResizer = null; windowResizer = null;
} }
oldStyleValues = null;
borderShared = null;
} }
@Override @Override
@@ -130,15 +146,46 @@ public class FlatInternalFrameUI
return new FlatBorderListener(); return new FlatBorderListener();
} }
@Override
protected PropertyChangeListener createPropertyChangeListener() {
return FlatStylingSupport.createPropertyChangeListener( frame, this::applyStyle,
super.createPropertyChangeListener() );
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, frame, borderShared );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, frame.getBorder() );
}
//---- class FlatInternalFrameBorder -------------------------------------- //---- class FlatInternalFrameBorder --------------------------------------
public static class FlatInternalFrameBorder public static class FlatInternalFrameBorder
extends FlatEmptyBorder extends FlatEmptyBorder
implements StyleableBorder
{ {
private final Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" ); @Styleable protected Color activeBorderColor = UIManager.getColor( "InternalFrame.activeBorderColor" );
private final Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" ); @Styleable protected Color inactiveBorderColor = UIManager.getColor( "InternalFrame.inactiveBorderColor" );
private final int borderLineWidth = FlatUIUtils.getUIInt( "InternalFrame.borderLineWidth", 1 ); @Styleable protected int borderLineWidth = FlatUIUtils.getUIInt( "InternalFrame.borderLineWidth", 1 );
private final boolean dropShadowPainted = UIManager.getBoolean( "InternalFrame.dropShadowPainted" ); @Styleable protected boolean dropShadowPainted = UIManager.getBoolean( "InternalFrame.dropShadowPainted" );
private final FlatDropShadowBorder activeDropShadowBorder = new FlatDropShadowBorder( private final FlatDropShadowBorder activeDropShadowBorder = new FlatDropShadowBorder(
UIManager.getColor( "InternalFrame.activeDropShadowColor" ), UIManager.getColor( "InternalFrame.activeDropShadowColor" ),
@@ -153,6 +200,36 @@ public class FlatInternalFrameUI
super( UIManager.getInsets( "InternalFrame.borderMargins" ) ); super( UIManager.getInsets( "InternalFrame.borderMargins" ) );
} }
@Override
public Object applyStyleProperty( String key, Object value ) {
switch( key ) {
case "borderMargins": return applyStyleProperty( (Insets) value );
case "activeDropShadowColor": return activeDropShadowBorder.applyStyleProperty( "shadowColor", value );
case "activeDropShadowInsets": return activeDropShadowBorder.applyStyleProperty( "shadowInsets", value );
case "activeDropShadowOpacity": return activeDropShadowBorder.applyStyleProperty( "shadowOpacity", value );
case "inactiveDropShadowColor": return inactiveDropShadowBorder.applyStyleProperty( "shadowColor", value );
case "inactiveDropShadowInsets": return inactiveDropShadowBorder.applyStyleProperty( "shadowInsets", value );
case "inactiveDropShadowOpacity": return inactiveDropShadowBorder.applyStyleProperty( "shadowOpacity", value );
}
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
@Override
public Map<String, Class<?>> getStyleableInfos() {
Map<String, Class<?>> infos = new LinkedHashMap<>();
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
infos.put( "borderMargins", Insets.class );
infos.put( "activeDropShadowColor", Color.class );
infos.put( "activeDropShadowInsets", Insets.class );
infos.put( "activeDropShadowOpacity", float.class );
infos.put( "inactiveDropShadowColor", Color.class );
infos.put( "inactiveDropShadowInsets", Insets.class );
infos.put( "inactiveDropShadowOpacity", float.class );
return infos;
}
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
if( c instanceof JInternalFrame && ((JInternalFrame)c).isMaximum() ) { if( c instanceof JInternalFrame && ((JInternalFrame)c).isMaximum() ) {

View File

@@ -24,6 +24,7 @@ import java.awt.Rectangle;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -33,7 +34,10 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicHTML; import javax.swing.plaf.basic.BasicHTML;
import javax.swing.plaf.basic.BasicLabelUI; import javax.swing.plaf.basic.BasicLabelUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -54,13 +58,32 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatLabelUI public class FlatLabelUI
extends BasicLabelUI extends BasicLabelUI
implements StyleableUI
{ {
private Color disabledForeground; @Styleable protected Color disabledForeground;
private final boolean shared;
private boolean defaults_initialized = false; private boolean defaults_initialized = false;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatLabelUI.class, FlatLabelUI::new ); return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatLabelUI.class, () -> new FlatLabelUI( true ) )
: new FlatLabelUI( false );
}
/**
* @since 2
*/
protected FlatLabelUI( boolean shared ) {
this.shared = shared;
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( (JLabel) c, FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -77,7 +100,9 @@ public class FlatLabelUI
@Override @Override
protected void uninstallDefaults( JLabel c ) { protected void uninstallDefaults( JLabel c ) {
super.uninstallDefaults( c ); super.uninstallDefaults( c );
defaults_initialized = false; defaults_initialized = false;
oldStyleValues = null;
} }
@Override @Override
@@ -94,10 +119,44 @@ public class FlatLabelUI
if( name == "text" || name == "font" || name == "foreground" ) { if( name == "text" || name == "font" || name == "foreground" ) {
JLabel label = (JLabel) e.getSource(); JLabel label = (JLabel) e.getSource();
updateHTMLRenderer( label, label.getText(), true ); updateHTMLRenderer( label, label.getText(), true );
} else if( name.equals( FlatClientProperties.STYLE ) ) {
JLabel label = (JLabel) e.getSource();
Object style = e.getNewValue();
if( style != null && shared ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
label.updateUI();
} else
applyStyle( label, style );
label.revalidate();
label.repaint();
} else } else
super.propertyChange( e ); super.propertyChange( e );
} }
/**
* @since 2
*/
protected void applyStyle( JLabel c, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
(key, value) -> applyStyleProperty( c, key, value ) );
}
/**
* @since 2
*/
protected Object applyStyleProperty( JLabel c, String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, c, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
/** /**
* Checks whether text contains HTML tags that use "absolute-size" keywords * Checks whether text contains HTML tags that use "absolute-size" keywords
* (e.g. "x-large") for font-size in default style sheet * (e.g. "x-large") for font-size in default style sheet

View File

@@ -61,8 +61,8 @@ public class FlatLineBorder
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
g2.setColor( lineColor ); g2.setColor( getLineColor() );
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0f, scale( lineThickness ), 0f ); FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0f, scale( getLineThickness() ), 0f );
} finally { } finally {
g2.dispose(); g2.dispose();
} }

View File

@@ -16,11 +16,15 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets;
import java.util.function.Function;
import javax.swing.JList; import javax.swing.JList;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ListUI;
/** /**
* Cell border for {@link javax.swing.DefaultListCellRenderer} * Cell border for {@link javax.swing.DefaultListCellRenderer}
@@ -33,12 +37,54 @@ import javax.swing.UIManager;
public class FlatListCellBorder public class FlatListCellBorder
extends FlatLineBorder extends FlatLineBorder
{ {
final boolean showCellFocusIndicator = UIManager.getBoolean( "List.showCellFocusIndicator" ); protected boolean showCellFocusIndicator = UIManager.getBoolean( "List.showCellFocusIndicator" );
private Component c;
protected FlatListCellBorder() { protected FlatListCellBorder() {
super( UIManager.getInsets( "List.cellMargins" ), UIManager.getColor( "List.cellFocusColor" ) ); super( UIManager.getInsets( "List.cellMargins" ), UIManager.getColor( "List.cellFocusColor" ) );
} }
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
Insets m = getStyleFromListUI( c, ui -> ui.cellMargins );
if( m != null )
return scaleInsets( c, insets, m.top, m.left, m.bottom, m.right );
return super.getBorderInsets( c, insets );
}
@Override
public Color getLineColor() {
if( c != null ) {
Color color = getStyleFromListUI( c, ui -> ui.cellFocusColor );
if( color != null )
return color;
}
return super.getLineColor();
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
this.c = c;
super.paintBorder( c, g, x, y, width, height );
this.c = null;
}
/**
* Because this borders are always shared for all lists,
* get border specific style from FlatListUI.
*/
static <T> T getStyleFromListUI( Component c, Function<FlatListUI, T> f ) {
JList<?> list = (JList<?>) SwingUtilities.getAncestorOfClass( JList.class, c );
if( list != null ) {
ListUI ui = list.getUI();
if( ui instanceof FlatListUI )
return f.apply( (FlatListUI) ui );
}
return null;
}
//---- class Default ------------------------------------------------------ //---- class Default ------------------------------------------------------
/** /**
@@ -74,6 +120,8 @@ public class FlatListCellBorder
{ {
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Boolean b = getStyleFromListUI( c, ui -> ui.showCellFocusIndicator );
boolean showCellFocusIndicator = (b != null) ? b : this.showCellFocusIndicator;
if( !showCellFocusIndicator ) if( !showCellFocusIndicator )
return; return;

View File

@@ -18,14 +18,18 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent; 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.BasicListUI; import javax.swing.plaf.basic.BasicListUI;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}. * Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
@@ -65,16 +69,31 @@ import com.formdev.flatlaf.FlatClientProperties;
*/ */
public class FlatListUI public class FlatListUI
extends BasicListUI extends BasicListUI
implements StyleableUI
{ {
protected Color selectionBackground; @Styleable protected Color selectionBackground;
protected Color selectionForeground; @Styleable protected Color selectionForeground;
protected Color selectionInactiveBackground; @Styleable protected Color selectionInactiveBackground;
protected Color selectionInactiveForeground; @Styleable protected Color selectionInactiveForeground;
// for FlatListCellBorder
@Styleable protected Insets cellMargins;
@Styleable protected Color cellFocusColor;
@Styleable protected boolean showCellFocusIndicator;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatListUI(); return new FlatListUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -95,17 +114,8 @@ public class FlatListUI
selectionForeground = null; selectionForeground = null;
selectionInactiveBackground = null; selectionInactiveBackground = null;
selectionInactiveForeground = null; selectionInactiveForeground = null;
}
@Override oldStyleValues = null;
protected PropertyChangeListener createPropertyChangeListener() {
PropertyChangeListener superListener = super.createPropertyChangeListener();
return e -> {
superListener.propertyChange( e );
if( FlatClientProperties.COMPONENT_FOCUS_OWNER.equals( e.getPropertyName() ) )
toggleSelectionColors();
};
} }
@Override @Override
@@ -129,6 +139,71 @@ public class FlatListUI
}; };
} }
@Override
protected PropertyChangeListener createPropertyChangeListener() {
PropertyChangeListener superListener = super.createPropertyChangeListener();
return e -> {
superListener.propertyChange( e );
switch( e.getPropertyName() ) {
case FlatClientProperties.COMPONENT_FOCUS_OWNER:
toggleSelectionColors();
break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
list.revalidate();
list.repaint();
break;
}
};
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
Color oldSelectionBackground = selectionBackground;
Color oldSelectionForeground = selectionForeground;
Color oldSelectionInactiveBackground = selectionInactiveBackground;
Color oldSelectionInactiveForeground = selectionInactiveForeground;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
// update selection background
if( selectionBackground != oldSelectionBackground ) {
Color selBg = list.getSelectionBackground();
if( selBg == oldSelectionBackground )
list.setSelectionBackground( selectionBackground );
else if( selBg == oldSelectionInactiveBackground )
list.setSelectionBackground( selectionInactiveBackground );
}
// update selection foreground
if( selectionForeground != oldSelectionForeground ) {
Color selFg = list.getSelectionForeground();
if( selFg == oldSelectionForeground )
list.setSelectionForeground( selectionForeground );
else if( selFg == oldSelectionInactiveForeground )
list.setSelectionForeground( selectionInactiveForeground );
}
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, list, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
/** /**
* Toggle selection colors from focused to inactive and vice versa. * Toggle selection colors from focused to inactive and vice versa.
* *

View File

@@ -29,7 +29,7 @@ import javax.swing.plaf.basic.BasicBorders;
public class FlatMarginBorder public class FlatMarginBorder
extends BasicBorders.MarginBorder extends BasicBorders.MarginBorder
{ {
private final int left, right, top, bottom; protected int left, right, top, bottom;
public FlatMarginBorder() { public FlatMarginBorder() {
left = right = top = bottom = 0; left = right = top = bottom = 0;

View File

@@ -21,8 +21,11 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.util.Map;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
/** /**
* Border for {@link javax.swing.JMenuBar}. * Border for {@link javax.swing.JMenuBar}.
@@ -33,8 +36,22 @@ import javax.swing.UIManager;
*/ */
public class FlatMenuBarBorder public class FlatMenuBarBorder
extends FlatMarginBorder extends FlatMarginBorder
implements StyleableBorder
{ {
private final Color borderColor = UIManager.getColor( "MenuBar.borderColor" ); @Styleable protected Color borderColor = UIManager.getColor( "MenuBar.borderColor" );
/**
* @since 2
*/
@Override
public Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
@Override
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {

View File

@@ -18,8 +18,12 @@ package com.formdev.flatlaf.ui;
import java.awt.Color; import java.awt.Color;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.ActionMap; import javax.swing.ActionMap;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -35,7 +39,10 @@ import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicMenuBarUI; import javax.swing.plaf.basic.BasicMenuBarUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
/** /**
@@ -47,13 +54,30 @@ import com.formdev.flatlaf.util.SystemInfo;
* @uiDefault MenuBar.background Color * @uiDefault MenuBar.background Color
* @uiDefault MenuBar.foreground Color * @uiDefault MenuBar.foreground Color
* @uiDefault MenuBar.border Border * @uiDefault MenuBar.border Border
*
* <!-- FlatMenuBarUI -->
*
* @uiDefault TitlePane.unifiedBackground boolean * @uiDefault TitlePane.unifiedBackground boolean
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatMenuBarUI public class FlatMenuBarUI
extends BasicMenuBarUI extends BasicMenuBarUI
implements StyleableUI
{ {
// used in FlatMenuItemBorder
/** @since 2 */ @Styleable protected Insets itemMargins;
// used in FlatMenuUI
/** @since 2 */ @Styleable protected Color hoverBackground;
/** @since 2 */ @Styleable protected Color underlineSelectionBackground;
/** @since 2 */ @Styleable protected Color underlineSelectionColor;
/** @since 2 */ @Styleable protected int underlineSelectionHeight = -1;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatMenuBarUI(); return new FlatMenuBarUI();
} }
@@ -63,6 +87,13 @@ public class FlatMenuBarUI
* Do not add any functionality here. * Do not add any functionality here.
*/ */
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -70,6 +101,31 @@ public class FlatMenuBarUI
LookAndFeel.installProperty( menuBar, "opaque", false ); LookAndFeel.installProperty( menuBar, "opaque", false );
} }
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
oldStyleValues = null;
borderShared = null;
}
@Override
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
menuBar, this::applyStyle, null );
menuBar.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
menuBar.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = null;
}
@Override @Override
protected void installKeyboardActions() { protected void installKeyboardActions() {
super.installKeyboardActions(); super.installKeyboardActions();
@@ -82,6 +138,30 @@ public class FlatMenuBarUI
map.put( "takeFocus", new TakeFocus() ); map.put( "takeFocus", new TakeFocus() );
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, menuBar, borderShared );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, menuBar.getBorder() );
}
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
// paint background // paint background

View File

@@ -18,9 +18,11 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Component; import java.awt.Component;
import java.awt.Container;
import java.awt.Insets; import java.awt.Insets;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.MenuBarUI;
/** /**
* Border for {@link javax.swing.JMenu}, {@link javax.swing.JMenuItem}, * Border for {@link javax.swing.JMenu}, {@link javax.swing.JMenuItem},
@@ -33,15 +35,22 @@ import javax.swing.UIManager;
public class FlatMenuItemBorder public class FlatMenuItemBorder
extends FlatMarginBorder extends FlatMarginBorder
{ {
// only used if parent menubar is not a instance of FlatMenuBarUI
private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" ); private final Insets menuBarItemMargins = UIManager.getInsets( "MenuBar.itemMargins" );
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
if( c.getParent() instanceof JMenuBar ) { Container parent = c.getParent();
insets.top = scale( menuBarItemMargins.top ); if( parent instanceof JMenuBar ) {
insets.left = scale( menuBarItemMargins.left ); // get margins from FlatMenuBarUI to allow styling
insets.bottom = scale( menuBarItemMargins.bottom ); MenuBarUI ui = ((JMenuBar)parent).getUI();
insets.right = scale( menuBarItemMargins.right ); Insets margins = (ui instanceof FlatMenuBarUI && ((FlatMenuBarUI)ui).itemMargins != null)
? ((FlatMenuBarUI)ui).itemMargins
: this.menuBarItemMargins;
insets.top = scale( margins.top );
insets.left = scale( margins.left );
insets.bottom = scale( margins.bottom );
insets.right = scale( margins.right );
return insets; return insets;
} else } else
return super.getBorderInsets( c, insets ); return super.getBorderInsets( c, insets );

View File

@@ -30,6 +30,7 @@ import java.awt.Rectangle;
import java.awt.event.InputEvent; import java.awt.event.InputEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator;
import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
@@ -39,6 +40,10 @@ import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicHTML; import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.View; import javax.swing.text.View;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatCheckBoxMenuItemIcon;
import com.formdev.flatlaf.icons.FlatMenuArrowIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.DerivedColor; import com.formdev.flatlaf.util.DerivedColor;
import com.formdev.flatlaf.util.Graphics2DProxy; import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
@@ -57,33 +62,32 @@ import com.formdev.flatlaf.util.SystemInfo;
* @uiDefault MenuItem.underlineSelectionCheckBackground Color * @uiDefault MenuItem.underlineSelectionCheckBackground Color
* @uiDefault MenuItem.underlineSelectionColor Color * @uiDefault MenuItem.underlineSelectionColor Color
* @uiDefault MenuItem.underlineSelectionHeight int * @uiDefault MenuItem.underlineSelectionHeight int
* @uiDefault MenuItem.selectionBackground Color
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatMenuItemRenderer public class FlatMenuItemRenderer
{ {
protected final JMenuItem menuItem; protected final JMenuItem menuItem;
protected final Icon checkIcon; protected Icon checkIcon;
protected final Icon arrowIcon; protected Icon arrowIcon;
protected final Font acceleratorFont; protected final Font acceleratorFont;
protected final String acceleratorDelimiter; protected final String acceleratorDelimiter;
protected final int minimumWidth = UIManager.getInt( "MenuItem.minimumWidth" ); @Styleable protected int minimumWidth = UIManager.getInt( "MenuItem.minimumWidth" );
protected final Dimension minimumIconSize; @Styleable protected Dimension minimumIconSize;
protected final int textAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textAcceleratorGap", 28 ); @Styleable protected int textAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textAcceleratorGap", 28 );
protected final int textNoAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textNoAcceleratorGap", 6 ); @Styleable protected int textNoAcceleratorGap = FlatUIUtils.getUIInt( "MenuItem.textNoAcceleratorGap", 6 );
protected final int acceleratorArrowGap = FlatUIUtils.getUIInt( "MenuItem.acceleratorArrowGap", 2 ); @Styleable protected int acceleratorArrowGap = FlatUIUtils.getUIInt( "MenuItem.acceleratorArrowGap", 2 );
protected final Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" ); @Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
protected final Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" ); @Styleable protected Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );
protected final Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" ); @Styleable protected Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
protected final Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" ); @Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
protected final Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" ); @Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
protected final int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" ); @Styleable protected int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" );
protected final Color selectionBackground = UIManager.getColor( "MenuItem.selectionBackground" ); private boolean iconsShared = true;
protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon, protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter ) Font acceleratorFont, String acceleratorDelimiter )
@@ -98,6 +102,67 @@ public class FlatMenuItemRenderer
this.minimumIconSize = (minimumIconSize != null) ? minimumIconSize : new Dimension( 16, 16 ); this.minimumIconSize = (minimumIconSize != null) ? minimumIconSize : new Dimension( 16, 16 );
} }
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
// style icon
if( key.startsWith( "icon." ) || key.equals( "selectionForeground" ) ) {
if( iconsShared ) {
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
checkIcon = FlatStylingSupport.cloneIcon( checkIcon );
if( arrowIcon instanceof FlatMenuArrowIcon )
arrowIcon = FlatStylingSupport.cloneIcon( arrowIcon );
iconsShared = false;
}
if( key.startsWith( "icon." ) ) {
String key2 = key.substring( "icon.".length() );
try {
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
return ((FlatCheckBoxMenuItemIcon)checkIcon).applyStyleProperty( key2, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
try {
if( arrowIcon instanceof FlatMenuArrowIcon )
return ((FlatMenuArrowIcon)arrowIcon).applyStyleProperty( key2, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
// keys with prefix "icon." are only for icons
throw new UnknownStyleException( key );
} else if( key.equals( "selectionForeground" ) ) {
// special case: same key is used in icons and in menuitem
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
((FlatCheckBoxMenuItemIcon)checkIcon).applyStyleProperty( key, value );
if( arrowIcon instanceof FlatMenuArrowIcon )
((FlatMenuArrowIcon)arrowIcon).applyStyleProperty( key, value );
// throw exception because the caller should also apply this key
throw new UnknownStyleException( key );
}
}
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
if( checkIcon instanceof FlatCheckBoxMenuItemIcon )
FlatStylingSupport.putAllPrefixKey( infos, "icon.", ((FlatCheckBoxMenuItemIcon)checkIcon).getStyleableInfos() );
if( arrowIcon instanceof FlatMenuArrowIcon )
FlatStylingSupport.putAllPrefixKey( infos, "icon.", ((FlatMenuArrowIcon)arrowIcon).getStyleableInfos() );
infos.remove( "icon.selectionForeground" );
return infos;
}
protected Dimension getPreferredMenuItemSize() { protected Dimension getPreferredMenuItemSize() {
int width = 0; int width = 0;
int height = 0; int height = 0;
@@ -254,7 +319,7 @@ debug*/
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground ); paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
if( underlineSelection && isArmedOrSelected( menuItem ) ) if( underlineSelection && isArmedOrSelected( menuItem ) )
paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight ); paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground ); paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground ); paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground ); paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
if( !isTopLevelMenu( menuItem ) ) if( !isTopLevelMenu( menuItem ) )
@@ -301,7 +366,7 @@ debug*/
return FlatUIUtils.deriveColor( background, baseColor ); return FlatUIUtils.deriveColor( background, baseColor );
} }
protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color checkBackground ) { protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color checkBackground, Color selectionBackground ) {
// if checkbox/radiobutton menu item is selected and also has a custom icon, // if checkbox/radiobutton menu item is selected and also has a custom icon,
// then use filled icon background to indicate selection (instead of using checkIcon) // then use filled icon background to indicate selection (instead of using checkIcon)
if( menuItem.isSelected() && checkIcon != null && icon != checkIcon ) { if( menuItem.isSelected() && checkIcon != null && icon != checkIcon ) {

View File

@@ -16,13 +16,20 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.beans.PropertyChangeListener;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicMenuItemUI; import javax.swing.plaf.basic.BasicMenuItemUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenuItem}. * Provides the Flat LaF UI delegate for {@link javax.swing.JMenuItem}.
@@ -54,13 +61,22 @@ import javax.swing.plaf.basic.BasicMenuItemUI;
*/ */
public class FlatMenuItemUI public class FlatMenuItemUI
extends BasicMenuItemUI extends BasicMenuItemUI
implements StyleableUI
{ {
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatMenuItemUI(); return new FlatMenuItemUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( menuItem ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -75,12 +91,72 @@ public class FlatMenuItemUI
super.uninstallDefaults(); super.uninstallDefaults();
renderer = null; renderer = null;
oldStyleValues = null;
} }
protected FlatMenuItemRenderer createRenderer() { protected FlatMenuItemRenderer createRenderer() {
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter ); return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
} }
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) );
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
return applyStyleProperty( this, menuItem, key, value );
}
static Object applyStyleProperty( BasicMenuItemUI ui, JMenuItem menuItem, String key, Object value ) {
switch( key ) {
// BasicMenuItemUI
case "selectionBackground":
case "selectionForeground":
case "disabledForeground":
case "acceleratorForeground":
case "acceleratorSelectionForeground":
return FlatStylingSupport.applyToField( ui, key, key, value );
default:
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( ui, menuItem, key, value );
}
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return getStyleableInfos( renderer );
}
static Map<String, Class<?>> getStyleableInfos( FlatMenuItemRenderer renderer ) {
Map<String, Class<?>> infos = new LinkedHashMap<>();
infos.put( "selectionBackground", Color.class );
infos.put( "selectionForeground", Color.class );
infos.put( "disabledForeground", Color.class );
infos.put( "acceleratorForeground", Color.class );
infos.put( "acceleratorSelectionForeground", Color.class );
infos.putAll( renderer.getStyleableInfos() );
return infos;
}
@Override @Override
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) { protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
return renderer.getPreferredMenuItemSize(); return renderer.getPreferredMenuItemSize();

View File

@@ -21,16 +21,23 @@ import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.function.Function;
import javax.swing.ButtonModel; import javax.swing.ButtonModel;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.event.MouseInputListener; import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.MenuBarUI;
import javax.swing.plaf.basic.BasicMenuUI; import javax.swing.plaf.basic.BasicMenuUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JMenu}. * Provides the Flat LaF UI delegate for {@link javax.swing.JMenu}.
@@ -60,10 +67,10 @@ import javax.swing.plaf.basic.BasicMenuUI;
* <!-- FlatMenuUI --> * <!-- FlatMenuUI -->
* *
* @uiDefault MenuItem.iconTextGap int * @uiDefault MenuItem.iconTextGap int
* @uiDefault MenuBar.hoverBackground Color
* *
* <!-- FlatMenuRenderer --> * <!-- FlatMenuRenderer -->
* *
* @uiDefault MenuBar.hoverBackground Color
* @uiDefault MenuBar.underlineSelectionBackground Color * @uiDefault MenuBar.underlineSelectionBackground Color
* @uiDefault MenuBar.underlineSelectionColor Color * @uiDefault MenuBar.underlineSelectionColor Color
* @uiDefault MenuBar.underlineSelectionHeight int * @uiDefault MenuBar.underlineSelectionHeight int
@@ -72,14 +79,22 @@ import javax.swing.plaf.basic.BasicMenuUI;
*/ */
public class FlatMenuUI public class FlatMenuUI
extends BasicMenuUI extends BasicMenuUI
implements StyleableUI
{ {
private Color hoverBackground;
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatMenuUI(); return new FlatMenuUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( menuItem ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -88,7 +103,6 @@ public class FlatMenuUI
menuItem.setRolloverEnabled( true ); menuItem.setRolloverEnabled( true );
hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
renderer = createRenderer(); renderer = createRenderer();
} }
@@ -96,8 +110,8 @@ public class FlatMenuUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
hoverBackground = null;
renderer = null; renderer = null;
oldStyleValues = null;
} }
protected FlatMenuItemRenderer createRenderer() { protected FlatMenuItemRenderer createRenderer() {
@@ -129,6 +143,39 @@ public class FlatMenuUI
}; };
} }
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) );
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
return FlatMenuItemUI.applyStyleProperty( this, menuItem, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatMenuItemUI.getStyleableInfos( renderer );
}
@Override @Override
public Dimension getMinimumSize( JComponent c ) { public Dimension getMinimumSize( JComponent c ) {
// avoid that top-level menus (in menu bar) are made smaller if horizontal space is rare // avoid that top-level menus (in menu bar) are made smaller if horizontal space is rare
@@ -153,9 +200,10 @@ public class FlatMenuUI
protected class FlatMenuRenderer protected class FlatMenuRenderer
extends FlatMenuItemRenderer extends FlatMenuItemRenderer
{ {
protected final Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground ); protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
protected final Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor ); protected Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
protected final int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight ); protected Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon, protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter ) Font acceleratorFont, String acceleratorDelimiter )
@@ -165,27 +213,39 @@ public class FlatMenuUI
@Override @Override
protected void paintBackground( Graphics g, Color selectionBackground ) { protected void paintBackground( Graphics g, Color selectionBackground ) {
if( isUnderlineSelection() && ((JMenu)menuItem).isTopLevelMenu() ) if( ((JMenu)menuItem).isTopLevelMenu() ) {
selectionBackground = menuBarUnderlineSelectionBackground; if( isUnderlineSelection() )
selectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground );
ButtonModel model = menuItem.getModel(); ButtonModel model = menuItem.getModel();
if( model.isRollover() && !model.isArmed() && !model.isSelected() && if( model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled() ) {
model.isEnabled() && ((JMenu)menuItem).isTopLevelMenu() ) g.setColor( deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) ) );
{ g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
g.setColor( deriveBackground( hoverBackground ) ); return;
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() ); }
} else }
super.paintBackground( g, selectionBackground );
super.paintBackground( g, selectionBackground );
} }
@Override @Override
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) { protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) { if( ((JMenu)menuItem).isTopLevelMenu() ) {
underlineSelectionColor = menuBarUnderlineSelectionColor; underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor );
underlineSelectionHeight = menuBarUnderlineSelectionHeight; underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1)
? ui.underlineSelectionHeight : null, menuBarUnderlineSelectionHeight );
} }
super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight ); super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
} }
private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue ) {
MenuBarUI ui = ((JMenuBar)menuItem.getParent()).getUI();
if( !(ui instanceof FlatMenuBarUI) )
return defaultValue;
T value = f.apply( (FlatMenuBarUI) ui );
return (value != null) ? value : defaultValue;
}
} }
} }

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Shape; import java.awt.Shape;
@@ -23,6 +24,7 @@ import java.awt.Toolkit;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.KeyListener; import java.awt.event.KeyListener;
import java.util.Map;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.ActionMap; import javax.swing.ActionMap;
import javax.swing.Icon; import javax.swing.Icon;
@@ -36,6 +38,8 @@ import javax.swing.text.Element;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import javax.swing.text.PasswordView; import javax.swing.text.PasswordView;
import javax.swing.text.View; import javax.swing.text.View;
import com.formdev.flatlaf.icons.FlatCapsLockIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}. * Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
@@ -75,10 +79,11 @@ import javax.swing.text.View;
public class FlatPasswordFieldUI public class FlatPasswordFieldUI
extends FlatTextFieldUI extends FlatTextFieldUI
{ {
protected boolean showCapsLock; @Styleable protected boolean showCapsLock;
protected Icon capsLockIcon; protected Icon capsLockIcon;
private KeyListener capsLockListener; private KeyListener capsLockListener;
private boolean capsLockIconShared = true;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatPasswordFieldUI(); return new FlatPasswordFieldUI();
@@ -100,6 +105,7 @@ public class FlatPasswordFieldUI
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" ); showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" ); capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
capsLockIconShared = true;
} }
@Override @Override
@@ -155,6 +161,32 @@ public class FlatPasswordFieldUI
} }
} }
/**
* @since 2
*/
@Override
protected Object applyStyleProperty( String key, Object value ) {
if( key.equals( "capsLockIconColor" ) && capsLockIcon instanceof FlatCapsLockIcon ) {
if( capsLockIconShared ) {
capsLockIcon = FlatStylingSupport.cloneIcon( capsLockIcon );
capsLockIconShared = false;
}
return ((FlatCapsLockIcon)capsLockIcon).applyStyleProperty( key, value );
}
return super.applyStyleProperty( key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = super.getStyleableInfos( c );
infos.put( "capsLockIconColor", Color.class );
return infos;
}
@Override @Override
public View create( Element elem ) { public View create( Element elem ) {
return new PasswordView( elem ); return new PasswordView( elem );

View File

@@ -16,11 +16,16 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Container; import java.awt.Container;
import java.awt.Insets; import java.awt.Insets;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableBorder;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -33,12 +38,44 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatPopupMenuBorder public class FlatPopupMenuBorder
extends FlatLineBorder extends FlatLineBorder
implements StyleableBorder
{ {
private Color borderColor;
public FlatPopupMenuBorder() { public FlatPopupMenuBorder() {
super( UIManager.getInsets( "PopupMenu.borderInsets" ), super( UIManager.getInsets( "PopupMenu.borderInsets" ),
UIManager.getColor( "PopupMenu.borderColor" ) ); UIManager.getColor( "PopupMenu.borderColor" ) );
} }
/**
* @since 2
*/
@Override
public Object applyStyleProperty( String key, Object value ) {
Object oldValue;
switch( key ) {
case "borderInsets": return applyStyleProperty( (Insets) value );
case "borderColor": oldValue = getLineColor(); borderColor = (Color) value; return oldValue;
}
throw new UnknownStyleException( key );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos() {
Map<String, Class<?>> infos = new LinkedHashMap<>();
infos.put( "borderInsets", Insets.class );
infos.put( "borderColor", Color.class );
return infos;
}
@Override
public Color getLineColor() {
return (borderColor != null) ? borderColor : super.getLineColor();
}
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
if( c instanceof Container && if( c instanceof Container &&

View File

@@ -39,7 +39,16 @@ public class FlatPopupMenuSeparatorUI
extends FlatSeparatorUI extends FlatSeparatorUI
{ {
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatPopupMenuSeparatorUI.class, FlatPopupMenuSeparatorUI::new ); return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatPopupMenuSeparatorUI.class, () -> new FlatPopupMenuSeparatorUI( true ) )
: new FlatPopupMenuSeparatorUI( false );
}
/**
* @since 2
*/
protected FlatPopupMenuSeparatorUI( boolean shared ) {
super( shared );
} }
@Override @Override

View File

@@ -16,9 +16,14 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPopupMenuUI; import javax.swing.plaf.basic.BasicPopupMenuUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPopupMenu}. * Provides the Flat LaF UI delegate for {@link javax.swing.JPopupMenu}.
@@ -34,8 +39,68 @@ import javax.swing.plaf.basic.BasicPopupMenuUI;
*/ */
public class FlatPopupMenuUI public class FlatPopupMenuUI
extends BasicPopupMenuUI extends BasicPopupMenuUI
implements StyleableUI
{ {
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatPopupMenuUI(); return new FlatPopupMenuUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override
public void uninstallUI( JComponent c ) {
super.uninstallUI( c );
oldStyleValues = null;
borderShared = null;
}
@Override
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( popupMenu, this::applyStyle, null );
popupMenu.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
popupMenu.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = null;
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, popupMenu, borderShared );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() );
}
} }

View File

@@ -25,12 +25,15 @@ import java.awt.Insets;
import java.awt.geom.Area; import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JProgressBar; import javax.swing.JProgressBar;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicProgressBarUI; import javax.swing.plaf.basic.BasicProgressBarUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -58,17 +61,26 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatProgressBarUI public class FlatProgressBarUI
extends BasicProgressBarUI extends BasicProgressBarUI
implements StyleableUI
{ {
protected int arc; @Styleable protected int arc;
protected Dimension horizontalSize; @Styleable protected Dimension horizontalSize;
protected Dimension verticalSize; @Styleable protected Dimension verticalSize;
private PropertyChangeListener propertyChangeListener; private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatProgressBarUI(); return new FlatProgressBarUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( progressBar ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -80,6 +92,13 @@ public class FlatProgressBarUI
verticalSize = UIManager.getDimension( "ProgressBar.verticalSize" ); verticalSize = UIManager.getDimension( "ProgressBar.verticalSize" );
} }
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
oldStyleValues = null;
}
@Override @Override
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
@@ -91,6 +110,12 @@ public class FlatProgressBarUI
progressBar.revalidate(); progressBar.revalidate();
progressBar.repaint(); progressBar.repaint();
break; break;
case STYLE:
applyStyle( e.getNewValue() );
progressBar.revalidate();
progressBar.repaint();
break;
} }
}; };
progressBar.addPropertyChangeListener( propertyChangeListener ); progressBar.addPropertyChangeListener( propertyChangeListener );
@@ -104,6 +129,28 @@ public class FlatProgressBarUI
propertyChangeListener = null; propertyChangeListener = null;
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, progressBar, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
Dimension size = super.getPreferredSize( c ); Dimension size = super.getPreferredSize( c );

View File

@@ -18,11 +18,15 @@ package com.formdev.flatlaf.ui;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI; import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JRadioButtonMenuItem}. * Provides the Flat LaF UI delegate for {@link javax.swing.JRadioButtonMenuItem}.
@@ -54,13 +58,22 @@ import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI;
*/ */
public class FlatRadioButtonMenuItemUI public class FlatRadioButtonMenuItemUI
extends BasicRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI
implements StyleableUI
{ {
private FlatMenuItemRenderer renderer; private FlatMenuItemRenderer renderer;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatRadioButtonMenuItemUI(); return new FlatRadioButtonMenuItemUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( menuItem ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -75,12 +88,46 @@ public class FlatRadioButtonMenuItemUI
super.uninstallDefaults(); super.uninstallDefaults();
renderer = null; renderer = null;
oldStyleValues = null;
} }
protected FlatMenuItemRenderer createRenderer() { protected FlatMenuItemRenderer createRenderer() {
return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter ); return new FlatMenuItemRenderer( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
} }
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) );
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
try {
return renderer.applyStyleProperty( key, value );
} catch ( UnknownStyleException ex ) {
// ignore
}
return FlatMenuItemUI.applyStyleProperty( this, menuItem, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatMenuItemUI.getStyleableInfos( renderer );
}
@Override @Override
protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) { protected Dimension getPreferredMenuItemSize( JComponent c, Icon checkIcon, Icon arrowIcon, int defaultTextIconGap ) {
return renderer.getPreferredMenuItemSize(); return renderer.getPreferredMenuItemSize();

View File

@@ -23,6 +23,8 @@ import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.CellRendererPane; import javax.swing.CellRendererPane;
@@ -30,8 +32,13 @@ import javax.swing.JComponent;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicRadioButtonUI; import javax.swing.plaf.basic.BasicRadioButtonUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.icons.FlatCheckBoxIcon; import com.formdev.flatlaf.icons.FlatCheckBoxIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -56,16 +63,36 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatRadioButtonUI public class FlatRadioButtonUI
extends BasicRadioButtonUI extends BasicRadioButtonUI
implements StyleableUI
{ {
protected int iconTextGap; protected int iconTextGap;
protected Color disabledText; @Styleable protected Color disabledText;
private Color defaultBackground; private Color defaultBackground;
private final boolean shared;
private boolean iconShared = true;
private boolean defaults_initialized = false; private boolean defaults_initialized = false;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, FlatRadioButtonUI::new ); return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatRadioButtonUI.class, () -> new FlatRadioButtonUI( true ) )
: new FlatRadioButtonUI( false );
}
/**
* @since 2
*/
protected FlatRadioButtonUI( boolean shared ) {
this.shared = shared;
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( (AbstractButton) c, FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -80,6 +107,7 @@ public class FlatRadioButtonUI
defaultBackground = UIManager.getColor( prefix + "background" ); defaultBackground = UIManager.getColor( prefix + "background" );
iconShared = true;
defaults_initialized = true; defaults_initialized = true;
} }
@@ -93,10 +121,78 @@ public class FlatRadioButtonUI
protected void uninstallDefaults( AbstractButton b ) { protected void uninstallDefaults( AbstractButton b ) {
super.uninstallDefaults( b ); super.uninstallDefaults( b );
oldStyleValues = null;
MigLayoutVisualPadding.uninstall( b ); MigLayoutVisualPadding.uninstall( b );
defaults_initialized = false; defaults_initialized = false;
} }
@Override
protected BasicButtonListener createButtonListener( AbstractButton b ) {
return new FlatRadioButtonListener( b );
}
/**
* @since 2
*/
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.STYLE:
Object style = e.getNewValue();
if( style != null && shared ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
b.updateUI();
} else
applyStyle( b, style );
b.revalidate();
b.repaint();
break;
}
}
/**
* @since 2
*/
protected void applyStyle( AbstractButton b, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
(key, value) -> applyStyleProperty( b, key, value ) );
}
/**
* @since 2
*/
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
// style icon
if( key.startsWith( "icon." ) ) {
if( !(icon instanceof FlatCheckBoxIcon) )
return new UnknownStyleException( key );
if( iconShared ) {
icon = FlatStylingSupport.cloneIcon( icon );
iconShared = false;
}
key = key.substring( "icon.".length() );
return ((FlatCheckBoxIcon)icon).applyStyleProperty( key, value );
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, b, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
if( icon instanceof FlatCheckBoxIcon ) {
for( Map.Entry<String, Class<?>> e : ((FlatCheckBoxIcon)icon).getStyleableInfos().entrySet() )
infos.put( "icon.".concat( e.getKey() ), e.getValue() );
}
return infos;
}
private static Insets tempInsets = new Insets( 0, 0, 0, 0 ); private static Insets tempInsets = new Insets( 0, 0, 0, 0 );
@Override @Override
@@ -182,4 +278,26 @@ public class FlatRadioButtonUI
? UIScale.scale( ((FlatCheckBoxIcon)getDefaultIcon()).focusWidth ) ? UIScale.scale( ((FlatCheckBoxIcon)getDefaultIcon()).focusWidth )
: 0; : 0;
} }
//---- class FlatRadioButtonListener --------------------------------------
/**
* @since 2
*/
protected class FlatRadioButtonListener
extends BasicButtonListener
{
private final AbstractButton b;
protected FlatRadioButtonListener( AbstractButton b ) {
super( b );
this.b = b;
}
@Override
public void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
FlatRadioButtonUI.this.propertyChange( b, e );
}
}
} }

View File

@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Component; import java.awt.Component;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/** /**
* Border for various components (e.g. {@link javax.swing.JComboBox}). * Border for various components (e.g. {@link javax.swing.JComboBox}).
@@ -29,7 +30,7 @@ import javax.swing.UIManager;
public class FlatRoundBorder public class FlatRoundBorder
extends FlatBorder extends FlatBorder
{ {
protected final int arc = UIManager.getInt( "Component.arc" ); @Styleable protected int arc = UIManager.getInt( "Component.arc" );
@Override @Override
protected int getArc( Component c ) { protected int getArc( Component c ) {

View File

@@ -24,6 +24,8 @@ import java.awt.Rectangle;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import javax.swing.InputMap; import javax.swing.InputMap;
import javax.swing.JButton; import javax.swing.JButton;
@@ -35,6 +37,8 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicScrollBarUI; import javax.swing.plaf.basic.BasicScrollBarUI;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -74,33 +78,46 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatScrollBarUI public class FlatScrollBarUI
extends BasicScrollBarUI extends BasicScrollBarUI
implements StyleableUI
{ {
protected Insets trackInsets; // overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private)
protected Insets thumbInsets; @Styleable protected boolean allowsAbsolutePositioning;
protected int trackArc;
protected int thumbArc;
protected Color hoverTrackColor;
protected Color hoverThumbColor;
protected boolean hoverThumbWithTrack;
protected Color pressedTrackColor;
protected Color pressedThumbColor;
protected boolean pressedThumbWithTrack;
protected boolean showButtons; @Styleable protected Insets trackInsets;
protected String arrowType; @Styleable protected Insets thumbInsets;
protected Color buttonArrowColor; @Styleable protected int trackArc;
protected Color buttonDisabledArrowColor; @Styleable protected int thumbArc;
protected Color hoverButtonBackground; @Styleable protected Color hoverTrackColor;
protected Color pressedButtonBackground; @Styleable protected Color hoverThumbColor;
@Styleable protected boolean hoverThumbWithTrack;
@Styleable protected Color pressedTrackColor;
@Styleable protected Color pressedThumbColor;
@Styleable protected boolean pressedThumbWithTrack;
@Styleable protected boolean showButtons;
@Styleable protected String arrowType;
@Styleable protected Color buttonArrowColor;
@Styleable protected Color buttonDisabledArrowColor;
@Styleable protected Color hoverButtonBackground;
@Styleable protected Color pressedButtonBackground;
private MouseAdapter hoverListener; private MouseAdapter hoverListener;
protected boolean hoverTrack; protected boolean hoverTrack;
protected boolean hoverThumb; protected boolean hoverThumb;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatScrollBarUI(); return new FlatScrollBarUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
@@ -123,6 +140,8 @@ public class FlatScrollBarUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
allowsAbsolutePositioning = super.getSupportsAbsolutePositioning();
trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" ); trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" );
thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" ); thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" );
trackArc = UIManager.getInt( "ScrollBar.trackArc" ); trackArc = UIManager.getInt( "ScrollBar.trackArc" );
@@ -163,6 +182,8 @@ public class FlatScrollBarUI
buttonDisabledArrowColor = null; buttonDisabledArrowColor = null;
hoverButtonBackground = null; hoverButtonBackground = null;
pressedButtonBackground = null; pressedButtonBackground = null;
oldStyleValues = null;
} }
@Override @Override
@@ -177,6 +198,12 @@ public class FlatScrollBarUI
scrollbar.repaint(); scrollbar.repaint();
break; break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
scrollbar.revalidate();
scrollbar.repaint();
break;
case "componentOrientation": case "componentOrientation":
// this is missing in BasicScrollBarUI.Handler.propertyChange() // this is missing in BasicScrollBarUI.Handler.propertyChange()
InputMap inputMap = (InputMap) UIManager.get( "ScrollBar.ancestorInputMap" ); InputMap inputMap = (InputMap) UIManager.get( "ScrollBar.ancestorInputMap" );
@@ -193,6 +220,50 @@ public class FlatScrollBarUI
}; };
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
if( incrButton instanceof FlatScrollBarButton )
((FlatScrollBarButton)incrButton).updateStyle();
if( decrButton instanceof FlatScrollBarButton )
((FlatScrollBarButton)decrButton).updateStyle();
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
Object oldValue;
switch( key ) {
// BasicScrollBarUI
case "track": oldValue = trackColor; trackColor = (Color) value; return oldValue;
case "thumb": oldValue = thumbColor; thumbColor = (Color) value; return oldValue;
case "width": oldValue = scrollBarWidth; scrollBarWidth = (int) value; return oldValue;
case "minimumThumbSize": oldValue = minimumThumbSize; minimumThumbSize = (Dimension) value; return oldValue;
case "maximumThumbSize": oldValue = maximumThumbSize; maximumThumbSize = (Dimension) value; return oldValue;
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, scrollbar, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = new LinkedHashMap<>();
infos.put( "track", Color.class );
infos.put( "thumb", Color.class );
infos.put( "width", int.class );
infos.put( "minimumThumbSize", Dimension.class );
infos.put( "maximumThumbSize", Dimension.class );
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
return infos;
}
@Override @Override
public Dimension getPreferredSize( JComponent c ) { public Dimension getPreferredSize( JComponent c ) {
return UIScale.scale( super.getPreferredSize( c ) ); return UIScale.scale( super.getPreferredSize( c ) );
@@ -295,6 +366,11 @@ public class FlatScrollBarUI
return UIScale.scale( FlatUIUtils.addInsets( super.getMaximumThumbSize(), thumbInsets ) ); return UIScale.scale( FlatUIUtils.addInsets( super.getMaximumThumbSize(), thumbInsets ) );
} }
@Override
public boolean getSupportsAbsolutePositioning() {
return allowsAbsolutePositioning;
}
//---- class ScrollBarHoverListener --------------------------------------- //---- class ScrollBarHoverListener ---------------------------------------
// using static field to disabling hover for other scroll bars // using static field to disabling hover for other scroll bars
@@ -368,6 +444,11 @@ public class FlatScrollBarUI
setRequestFocusEnabled( false ); setRequestFocusEnabled( false );
} }
protected void updateStyle() {
updateStyle( arrowType, buttonArrowColor, buttonDisabledArrowColor,
null, hoverButtonBackground, null, pressedButtonBackground );
}
@Override @Override
protected Color deriveBackground( Color background ) { protected Color deriveBackground( Color background ) {
return FlatUIUtils.deriveColor( background, scrollbar.getBackground() ); return FlatUIUtils.deriveColor( background, scrollbar.getBackground() );

View File

@@ -29,6 +29,8 @@ import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener; import java.awt.event.MouseWheelListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -46,6 +48,7 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicScrollPaneUI; import javax.swing.plaf.basic.BasicScrollPaneUI;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}. * Provides the Flat LaF UI delegate for {@link javax.swing.JScrollPane}.
@@ -66,9 +69,13 @@ import com.formdev.flatlaf.FlatClientProperties;
*/ */
public class FlatScrollPaneUI public class FlatScrollPaneUI
extends BasicScrollPaneUI extends BasicScrollPaneUI
implements StyleableUI
{ {
private Handler handler; private Handler handler;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatScrollPaneUI(); return new FlatScrollPaneUI();
} }
@@ -80,6 +87,8 @@ public class FlatScrollPaneUI
int focusWidth = UIManager.getInt( "Component.focusWidth" ); int focusWidth = UIManager.getInt( "Component.focusWidth" );
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 ); LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
applyStyle( FlatStylingSupport.getStyle( c ) );
MigLayoutVisualPadding.install( scrollpane ); MigLayoutVisualPadding.install( scrollpane );
} }
@@ -88,6 +97,9 @@ public class FlatScrollPaneUI
MigLayoutVisualPadding.uninstall( scrollpane ); MigLayoutVisualPadding.uninstall( scrollpane );
super.uninstallUI( c ); super.uninstallUI( c );
oldStyleValues = null;
borderShared = null;
} }
@Override @Override
@@ -272,7 +284,13 @@ public class FlatScrollPaneUI
((JButton)corner).setBorder( BorderFactory.createEmptyBorder() ); ((JButton)corner).setBorder( BorderFactory.createEmptyBorder() );
((JButton)corner).setFocusable( false ); ((JButton)corner).setFocusable( false );
} }
break; break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
scrollpane.revalidate();
scrollpane.repaint();
break;
} }
}; };
} }
@@ -283,6 +301,35 @@ public class FlatScrollPaneUI
return handler; return handler;
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
if( key.equals( "focusWidth" ) ) {
int focusWidth = (value instanceof Integer) ? (int) value : UIManager.getInt( "Component.focusWidth" );
LookAndFeel.installProperty( scrollpane, "opaque", focusWidth == 0 );
}
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, scrollpane, borderShared );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, scrollpane.getBorder() );
}
@Override @Override
protected void updateViewport( PropertyChangeEvent e ) { protected void updateViewport( PropertyChangeEvent e ) {
super.updateViewport( e ); super.updateViewport( e );

View File

@@ -21,11 +21,16 @@ import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSeparator; import javax.swing.JSeparator;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicSeparatorUI; import javax.swing.plaf.basic.BasicSeparatorUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JSeparator}. * Provides the Flat LaF UI delegate for {@link javax.swing.JSeparator}.
@@ -45,15 +50,39 @@ import javax.swing.plaf.basic.BasicSeparatorUI;
*/ */
public class FlatSeparatorUI public class FlatSeparatorUI
extends BasicSeparatorUI extends BasicSeparatorUI
implements StyleableUI
{ {
protected int height; @Styleable protected int height;
protected int stripeWidth; @Styleable protected int stripeWidth;
protected int stripeIndent; @Styleable protected int stripeIndent;
private final boolean shared;
private boolean defaults_initialized = false; private boolean defaults_initialized = false;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatSeparatorUI.class, FlatSeparatorUI::new ); return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatSeparatorUI.class, () -> new FlatSeparatorUI( true ) )
: new FlatSeparatorUI( false );
}
/**
* @since 2
*/
protected FlatSeparatorUI( boolean shared ) {
this.shared = shared;
}
protected String getPropertyPrefix() {
return "Separator";
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( (JSeparator) c, FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -73,11 +102,60 @@ public class FlatSeparatorUI
@Override @Override
protected void uninstallDefaults( JSeparator s ) { protected void uninstallDefaults( JSeparator s ) {
super.uninstallDefaults( s ); super.uninstallDefaults( s );
defaults_initialized = false; defaults_initialized = false;
oldStyleValues = null;
} }
protected String getPropertyPrefix() { @Override
return "Separator"; protected void installListeners( JSeparator s ) {
super.installListeners( s );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
s, style -> applyStyle( s, this, style ), null );
s.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
}
@Override
protected void uninstallListeners( JSeparator s ) {
super.uninstallListeners( s );
s.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = null;
}
private static void applyStyle( JSeparator s, FlatSeparatorUI ui, Object style ) {
if( style != null && ui.shared ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
s.updateUI();
} else
ui.applyStyle( s, style );
s.revalidate();
s.repaint();
}
/**
* @since 2
*/
protected void applyStyle( JSeparator s, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,
(key, value) -> applyStyleProperty( s, key, value ) );
}
/**
* @since 2
*/
protected Object applyStyleProperty( JSeparator s, String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, s, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
@Override @Override

View File

@@ -29,6 +29,8 @@ import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D; import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D; import java.awt.geom.Path2D;
import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSlider; import javax.swing.JSlider;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
@@ -36,6 +38,9 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicSliderUI; import javax.swing.plaf.basic.BasicSliderUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -75,23 +80,25 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatSliderUI public class FlatSliderUI
extends BasicSliderUI extends BasicSliderUI
implements StyleableUI
{ {
protected int trackWidth; @Styleable protected int trackWidth;
protected Dimension thumbSize; @Styleable protected Dimension thumbSize;
protected int focusWidth; @Styleable protected int focusWidth;
protected Color trackValueColor; @Styleable protected Color trackValueColor;
protected Color trackColor; @Styleable protected Color trackColor;
protected Color thumbColor; @Styleable protected Color thumbColor;
protected Color thumbBorderColor; @Styleable protected Color thumbBorderColor;
protected Color focusBaseColor; protected Color focusBaseColor;
protected Color focusedColor; @Styleable protected Color focusedColor;
protected Color focusedThumbBorderColor; @Styleable protected Color focusedThumbBorderColor;
protected Color hoverThumbColor; @Styleable protected Color hoverThumbColor;
protected Color pressedThumbColor; @Styleable protected Color pressedThumbColor;
protected Color disabledTrackColor; @Styleable protected Color disabledTrackColor;
protected Color disabledThumbColor; @Styleable protected Color disabledThumbColor;
protected Color disabledThumbBorderColor; @Styleable protected Color disabledThumbBorderColor;
@Styleable protected Color tickColor;
private Color defaultBackground; private Color defaultBackground;
private Color defaultForeground; private Color defaultForeground;
@@ -100,6 +107,7 @@ public class FlatSliderUI
protected boolean thumbPressed; protected boolean thumbPressed;
private Object[] oldRenderingHints; private Object[] oldRenderingHints;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatSliderUI(); return new FlatSliderUI();
@@ -109,6 +117,13 @@ public class FlatSliderUI
super( null ); super( null );
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( slider ) );
}
@Override @Override
protected void installDefaults( JSlider slider ) { protected void installDefaults( JSlider slider ) {
super.installDefaults( slider ); super.installDefaults( slider );
@@ -136,6 +151,7 @@ public class FlatSliderUI
disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" ); disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" );
disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" ); disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" );
disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" ); disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" );
tickColor = FlatUIUtils.getUIColor( "Slider.tickColor", Color.BLACK ); // see BasicSliderUI.paintTicks()
defaultBackground = UIManager.getColor( "Slider.background" ); defaultBackground = UIManager.getColor( "Slider.background" );
defaultForeground = UIManager.getColor( "Slider.foreground" ); defaultForeground = UIManager.getColor( "Slider.foreground" );
@@ -157,9 +173,12 @@ public class FlatSliderUI
disabledTrackColor = null; disabledTrackColor = null;
disabledThumbColor = null; disabledThumbColor = null;
disabledThumbBorderColor = null; disabledThumbBorderColor = null;
tickColor = null;
defaultBackground = null; defaultBackground = null;
defaultForeground = null; defaultForeground = null;
oldStyleValues = null;
} }
@Override @Override
@@ -167,6 +186,34 @@ public class FlatSliderUI
return new FlatTrackListener(); return new FlatTrackListener();
} }
@Override
protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) {
return FlatStylingSupport.createPropertyChangeListener( slider, this::applyStyle,
super.createPropertyChangeListener( slider ) );
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, slider, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
@Override @Override
public int getBaseline( JComponent c, int width, int height ) { public int getBaseline( JComponent c, int width, int height ) {
if( c == null ) if( c == null )
@@ -326,6 +373,19 @@ debug*/
((Graphics2D)g).fill( track ); ((Graphics2D)g).fill( track );
} }
@Override
public void paintTicks( Graphics g ) {
// because BasicSliderUI.paintTicks() always uses
// g.setColor( UIManager.getColor("Slider.tickColor") )
// we override this method and use our tickColor field to allow styling
super.paintTicks( new Graphics2DProxy( (Graphics2D) g ) {
@Override
public void setColor( Color c ) {
super.setColor( tickColor );
}
} );
}
@Override @Override
public void paintThumb( Graphics g ) { public void paintThumb( Graphics g ) {
Color thumbColor = getThumbColor(); Color thumbColor = getThumbColor();

View File

@@ -33,6 +33,8 @@ import java.awt.event.FocusListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSpinner; import javax.swing.JSpinner;
import javax.swing.JTextField; import javax.swing.JTextField;
@@ -43,6 +45,8 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource; import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicSpinnerUI; import javax.swing.plaf.basic.BasicSpinnerUI;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JSpinner}. * Provides the Flat LaF UI delegate for {@link javax.swing.JSpinner}.
@@ -79,29 +83,40 @@ import com.formdev.flatlaf.FlatClientProperties;
*/ */
public class FlatSpinnerUI public class FlatSpinnerUI
extends BasicSpinnerUI extends BasicSpinnerUI
implements StyleableUI
{ {
private Handler handler; private Handler handler;
protected int minimumWidth; @Styleable protected int minimumWidth;
protected String buttonStyle; @Styleable protected String buttonStyle;
protected String arrowType; @Styleable protected String arrowType;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color borderColor; @Styleable protected Color borderColor;
protected Color disabledBorderColor; @Styleable protected Color disabledBorderColor;
protected Color disabledBackground; @Styleable protected Color disabledBackground;
protected Color disabledForeground; @Styleable protected Color disabledForeground;
protected Color focusedBackground; @Styleable protected Color focusedBackground;
protected Color buttonBackground; @Styleable protected Color buttonBackground;
protected Color buttonArrowColor; @Styleable protected Color buttonArrowColor;
protected Color buttonDisabledArrowColor; @Styleable protected Color buttonDisabledArrowColor;
protected Color buttonHoverArrowColor; @Styleable protected Color buttonHoverArrowColor;
protected Color buttonPressedArrowColor; @Styleable protected Color buttonPressedArrowColor;
protected Insets padding; @Styleable protected Insets padding;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatSpinnerUI(); return new FlatSpinnerUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( spinner ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -143,6 +158,9 @@ public class FlatSpinnerUI
buttonPressedArrowColor = null; buttonPressedArrowColor = null;
padding = null; padding = null;
oldStyleValues = null;
borderShared = null;
MigLayoutVisualPadding.uninstall( spinner ); MigLayoutVisualPadding.uninstall( spinner );
} }
@@ -172,6 +190,32 @@ public class FlatSpinnerUI
return handler; return handler;
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
updateEditorPadding();
updateArrowButtonsStyle();
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, spinner, borderShared );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, spinner.getBorder() );
}
@Override @Override
protected JComponent createEditor() { protected JComponent createEditor() {
JComponent editor = super.createEditor(); JComponent editor = super.createEditor();
@@ -297,6 +341,15 @@ public class FlatSpinnerUI
return button; return button;
} }
private void updateArrowButtonsStyle() {
for( Component c : spinner.getComponents() ) {
if( c instanceof FlatArrowButton ) {
((FlatArrowButton)c).updateStyle( arrowType, buttonArrowColor,
buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null );
}
}
}
@Override @Override
public void update( Graphics g, JComponent c ) { public void update( Graphics g, JComponent c ) {
float focusWidth = FlatUIUtils.getBorderFocusWidth( c ); float focusWidth = FlatUIUtils.getBorderFocusWidth( c );
@@ -483,6 +536,12 @@ public class FlatSpinnerUI
case FlatClientProperties.MINIMUM_WIDTH: case FlatClientProperties.MINIMUM_WIDTH:
spinner.revalidate(); spinner.revalidate();
break; break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
spinner.revalidate();
spinner.repaint();
break;
} }
} }
} }

View File

@@ -23,6 +23,8 @@ import java.awt.Graphics;
import java.awt.Insets; import java.awt.Insets;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSplitPane; import javax.swing.JSplitPane;
@@ -32,6 +34,10 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI; import javax.swing.plaf.basic.BasicSplitPaneUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -66,16 +72,27 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatSplitPaneUI public class FlatSplitPaneUI
extends BasicSplitPaneUI extends BasicSplitPaneUI
implements StyleableUI
{ {
protected String arrowType; @Styleable protected String arrowType;
protected Color oneTouchArrowColor; @Styleable protected Color oneTouchArrowColor;
protected Color oneTouchHoverArrowColor; @Styleable protected Color oneTouchHoverArrowColor;
protected Color oneTouchPressedArrowColor; @Styleable protected Color oneTouchPressedArrowColor;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatSplitPaneUI(); return new FlatSplitPaneUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( splitPane ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
arrowType = UIManager.getString( "Component.arrowType" ); arrowType = UIManager.getString( "Component.arrowType" );
@@ -96,6 +113,24 @@ public class FlatSplitPaneUI
oneTouchArrowColor = null; oneTouchArrowColor = null;
oneTouchHoverArrowColor = null; oneTouchHoverArrowColor = null;
oneTouchPressedArrowColor = null; oneTouchPressedArrowColor = null;
oldStyleValues = null;
}
@Override
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::applyStyle, null );
splitPane.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
splitPane.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = null;
} }
@Override @Override
@@ -103,16 +138,50 @@ public class FlatSplitPaneUI
return new FlatSplitPaneDivider( this ); return new FlatSplitPaneDivider( this );
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
if( divider instanceof FlatSplitPaneDivider )
((FlatSplitPaneDivider)divider).updateStyle();
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
try {
if( divider instanceof FlatSplitPaneDivider )
return ((FlatSplitPaneDivider)divider).applyStyleProperty( key, value );
} catch( UnknownStyleException ex ) {
// ignore
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, splitPane, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = FlatStylingSupport.getAnnotatedStyleableInfos( this );
if( divider instanceof FlatSplitPaneDivider )
infos.putAll( ((FlatSplitPaneDivider)divider).getStyleableInfos() );
return infos;
}
//---- class FlatSplitPaneDivider ----------------------------------------- //---- class FlatSplitPaneDivider -----------------------------------------
protected class FlatSplitPaneDivider protected class FlatSplitPaneDivider
extends BasicSplitPaneDivider extends BasicSplitPaneDivider
{ {
protected final String style = UIManager.getString( "SplitPaneDivider.style" ); @Styleable protected String style = UIManager.getString( "SplitPaneDivider.style" );
protected final Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" ); @Styleable protected Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" );
protected final int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 ); @Styleable protected int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 );
protected final int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 ); @Styleable protected int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 );
protected final int gripGap = FlatUIUtils.getUIInt( "SplitPaneDivider.gripGap", 2 ); @Styleable protected int gripGap = FlatUIUtils.getUIInt( "SplitPaneDivider.gripGap", 2 );
protected FlatSplitPaneDivider( BasicSplitPaneUI ui ) { protected FlatSplitPaneDivider( BasicSplitPaneUI ui ) {
super( ui ); super( ui );
@@ -120,6 +189,27 @@ public class FlatSplitPaneUI
setLayout( new FlatDividerLayout() ); setLayout( new FlatDividerLayout() );
} }
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
public Map<String, Class<?>> getStyleableInfos() {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
void updateStyle() {
if( leftButton instanceof FlatOneTouchButton )
((FlatOneTouchButton)leftButton).updateStyle();
if( rightButton instanceof FlatOneTouchButton )
((FlatOneTouchButton)rightButton).updateStyle();
}
@Override @Override
public void setDividerSize( int newSize ) { public void setDividerSize( int newSize ) {
super.setDividerSize( UIScale.scale( newSize ) ); super.setDividerSize( UIScale.scale( newSize ) );
@@ -200,6 +290,11 @@ public class FlatSplitPaneUI
this.left = left; this.left = left;
} }
protected void updateStyle() {
updateStyle( arrowType, oneTouchArrowColor, null,
oneTouchHoverArrowColor, null, oneTouchPressedArrowColor, null );
}
@Override @Override
public int getDirection() { public int getDirection() {
return (orientation == JSplitPane.VERTICAL_SPLIT) return (orientation == JSplitPane.VERTICAL_SPLIT)

View File

@@ -0,0 +1,532 @@
/*
* Copyright 2021 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
*
* https://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.ui;
import java.beans.PropertyChangeListener;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.UIManager;
import javax.swing.border.Border;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
/**
* Support for styling components in CSS syntax.
*
* @author Karl Tauber
* @since 2
*/
public class FlatStylingSupport
{
/**
* Indicates that a field is intended to be used by FlatLaf styling support.
* <p>
* <strong>Do not rename fields annotated with this annotation.</strong>
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Styleable {
boolean dot() default false;
Class<?> type() default Void.class;
}
public interface StyleableUI {
Map<String, Class<?>> getStyleableInfos( JComponent c );
}
public interface StyleableBorder {
Object applyStyleProperty( String key, Object value );
Map<String, Class<?>> getStyleableInfos();
}
/**
* Parses styles in CSS syntax ("key1: value1; key2: value2; ..."),
* converts the value strings into binary and invokes the given function
* to apply the properties.
*
* @param oldStyleValues map of old values modified by the previous invocation, or {@code null}
* @param style the style in CSS syntax as string, or a Map, or {@code null}
* @param applyProperty function that is invoked to apply the properties;
* first parameter is the key, second the binary value;
* the function must return the old value
* @return map of old values modified by the given style, or {@code null}
* @throws UnknownStyleException on unknown style keys
* @throws IllegalArgumentException on syntax errors
* @throws ClassCastException if value type does not fit to expected type
*/
public static Map<String, Object> parseAndApply( Map<String, Object> oldStyleValues,
Object style, BiFunction<String, Object, Object> applyProperty )
throws UnknownStyleException, IllegalArgumentException
{
// restore previous values
if( oldStyleValues != null ) {
for( Map.Entry<String, Object> e : oldStyleValues.entrySet() )
applyProperty.apply( e.getKey(), e.getValue() );
}
// ignore empty style
if( style == null )
return null;
if( style instanceof String ) {
// handle style in CSS syntax
String str = (String) style;
if( str.trim().isEmpty() )
return null;
return applyStyle( parse( str ), applyProperty );
} else if( style instanceof Map ) {
// handle style of type Map
@SuppressWarnings( "unchecked" )
Map<String, Object> map = (Map<String, Object>) style;
return applyStyle( map, applyProperty );
} else
return null;
}
private static Map<String, Object> applyStyle( Map<String, Object> style,
BiFunction<String, Object, Object> applyProperty )
{
if( style.isEmpty() )
return null;
Map<String, Object> oldValues = new HashMap<>();
for( Map.Entry<String, Object> e : style.entrySet() ) {
String key = e.getKey();
Object newValue = e.getValue();
// handle key prefix
if( key.startsWith( "[" ) ) {
if( (SystemInfo.isWindows && key.startsWith( "[win]" )) ||
(SystemInfo.isMacOS && key.startsWith( "[mac]" )) ||
(SystemInfo.isLinux && key.startsWith( "[linux]" )) ||
(key.startsWith( "[light]" ) && !FlatLaf.isLafDark()) ||
(key.startsWith( "[dark]" ) && FlatLaf.isLafDark()) )
{
// prefix is known and enabled --> remove prefix
key = key.substring( key.indexOf( ']' ) + 1 );
} else
continue;
}
Object oldValue = applyProperty.apply( key, newValue );
oldValues.put( key, oldValue );
}
return oldValues;
}
/**
* Parses styles in CSS syntax ("key1: value1; key2: value2; ..."),
* converts the value strings into binary and returns all key/value pairs as map.
*
* @param style the style in CSS syntax, or {@code null}
* @return map of parsed styles, or {@code null}
* @throws IllegalArgumentException on syntax errors
*/
public static Map<String, Object> parse( String style )
throws IllegalArgumentException
{
if( style == null || style.trim().isEmpty() )
return null;
Map<String, Object> map = null;
// split style into parts and process them
for( String part : StringUtils.split( style, ';' ) ) {
// ignore empty parts
part = part.trim();
if( part.isEmpty() )
continue;
// find separator colon
int sepIndex = part.indexOf( ':' );
if( sepIndex < 0 )
throw new IllegalArgumentException( "missing colon in '" + part + "'" );
// split into key and value
String key = part.substring( 0, sepIndex ).trim();
String value = part.substring( sepIndex + 1 ).trim();
if( key.isEmpty() )
throw new IllegalArgumentException( "missing key in '" + part + "'" );
if( value.isEmpty() )
throw new IllegalArgumentException( "missing value in '" + part + "'" );
// parse value string and convert it into binary value
if( map == null )
map = new LinkedHashMap<>();
map.put( key, parseValue( key, value ) );
}
return map;
}
private static Object parseValue( String key, String value ) {
// simple reference
if( value.startsWith( "$" ) )
return UIManager.get( value.substring( 1 ) );
// remove key prefix for correct value type detection
// (e.g. "[light]padding" would not parse to Insets)
if( key.startsWith( "[" ) )
key = key.substring( key.indexOf( ']' ) + 1 );
// parse string
return FlatLaf.parseDefaultsValue( key, value, null );
}
/**
* Applies the given value to an annotated field of the given object.
* The field must be annotated with {@link Styleable}.
*
* @param obj the object
* @param key the name of the field
* @param value the new value
* @return the old value of the field
* @throws UnknownStyleException if object does not have a annotated field with given name
* @throws IllegalArgumentException if value type does not fit to expected type
*/
public static Object applyToAnnotatedObject( Object obj, String key, Object value )
throws UnknownStyleException, IllegalArgumentException
{
String fieldName = key;
int dotIndex = key.indexOf( '.' );
if( dotIndex >= 0 ) {
// remove first dot in key and change subsequent character to uppercase
fieldName = key.substring( 0, dotIndex )
+ Character.toUpperCase( key.charAt( dotIndex + 1 ) )
+ key.substring( dotIndex + 2 );
}
return applyToField( obj, fieldName, key, value, field -> {
Styleable styleable = field.getAnnotation( Styleable.class );
return styleable != null && styleable.dot() == (dotIndex >= 0);
} );
}
/**
* Applies the given value to a field of the given object.
*
* @param obj the object
* @param fieldName the name of the field
* @param key the key (only used for error reporting)
* @param value the new value
* @return the old value of the field
* @throws UnknownStyleException if object does not have a field with given name
* @throws IllegalArgumentException if value type does not fit to expected type
*/
static Object applyToField( Object obj, String fieldName, String key, Object value )
throws UnknownStyleException, IllegalArgumentException
{
return applyToField( obj, fieldName, key, value, null );
}
private static Object applyToField( Object obj, String fieldName, String key, Object value, Predicate<Field> predicate )
throws UnknownStyleException, IllegalArgumentException
{
Class<?> cls = obj.getClass();
for(;;) {
try {
Field f = cls.getDeclaredField( fieldName );
if( predicate == null || predicate.test( f ) ) {
if( !isValidField( f ) )
throw new IllegalArgumentException( "field '" + cls.getName() + "." + fieldName + "' is final or static" );
try {
// necessary to access protected fields in other packages
f.setAccessible( true );
// get old value and set new value
Object oldValue = f.get( obj );
f.set( obj, value );
return oldValue;
} catch( IllegalAccessException ex ) {
throw new IllegalArgumentException( "failed to access field '" + cls.getName() + "." + fieldName + "'" );
}
}
} catch( NoSuchFieldException ex ) {
// field not found in class --> try superclass
}
cls = cls.getSuperclass();
if( cls == null )
throw new UnknownStyleException( key );
if( predicate != null ) {
String superclassName = cls.getName();
if( superclassName.startsWith( "java." ) || superclassName.startsWith( "javax." ) )
throw new UnknownStyleException( key );
}
}
}
private static boolean isValidField( Field f ) {
int modifiers = f.getModifiers();
return (modifiers & (Modifier.FINAL|Modifier.STATIC)) == 0 && !f.isSynthetic();
}
/**
* Applies the given value to a property of the given object.
* Works only for properties that have public getter and setter methods.
* First the property getter is invoked to get the old value,
* then the property setter is invoked to set the new value.
*
* @param obj the object
* @param name the name of the property
* @param value the new value
* @return the old value of the property
* @throws UnknownStyleException if object does not have a property with given name
* @throws IllegalArgumentException if value type does not fit to expected type
*/
private static Object applyToProperty( Object obj, String name, Object value )
throws UnknownStyleException, IllegalArgumentException
{
Class<?> cls = obj.getClass();
String getterName = buildMethodName( "get", name );
String setterName = buildMethodName( "set", name );
try {
Method getter;
try {
getter = cls.getMethod( getterName );
} catch( NoSuchMethodException ex ) {
getter = cls.getMethod( buildMethodName( "is", name ) );
}
Method setter = cls.getMethod( setterName, getter.getReturnType() );
Object oldValue = getter.invoke( obj );
setter.invoke( obj, value );
return oldValue;
} catch( NoSuchMethodException ex ) {
throw new UnknownStyleException( name );
} catch( Exception ex ) {
throw new IllegalArgumentException( "failed to invoke property methods '" + cls.getName() + "."
+ getterName + "()' or '" + setterName + "(...)'", ex );
}
}
private static String buildMethodName( String prefix, String name ) {
int prefixLength = prefix.length();
int nameLength = name.length();
char[] chars = new char[prefixLength + nameLength];
prefix.getChars( 0, prefixLength, chars, 0 );
name.getChars( 0, nameLength, chars, prefixLength );
chars[prefixLength] = Character.toUpperCase( chars[prefixLength] );
return new String( chars );
}
/**
* Applies the given value to an annotated field of the given object
* or to a property of the given component.
* The field must be annotated with {@link Styleable}.
* The component property must have public getter and setter methods.
*
* @param obj the object
* @param comp the component, or {@code null}
* @param key the name of the field
* @param value the new value
* @return the old value of the field
* @throws UnknownStyleException if object does not have a annotated field with given name
* @throws IllegalArgumentException if value type does not fit to expected type
*/
public static Object applyToAnnotatedObjectOrComponent( Object obj, Object comp, String key, Object value ) {
try {
return applyToAnnotatedObject( obj, key, value );
} catch( UnknownStyleException ex ) {
try {
if( comp != null )
return applyToProperty( comp, key, value );
} catch( UnknownStyleException ex2 ) {
// ignore
}
throw ex;
}
}
static Object applyToAnnotatedObjectOrBorder( Object obj, String key, Object value,
JComponent c, AtomicBoolean borderShared )
{
try {
return applyToAnnotatedObject( obj, key, value );
} catch( UnknownStyleException ex ) {
// apply to border
Border border = c.getBorder();
if( border instanceof StyleableBorder ) {
if( borderShared.get() ) {
border = cloneBorder( border );
c.setBorder( border );
borderShared.set( false );
}
try {
return ((StyleableBorder)border).applyStyleProperty( key, value );
} catch( UnknownStyleException ex2 ) {
// ignore
}
}
// apply to component property
try {
return applyToProperty( c, key, value );
} catch( UnknownStyleException ex2 ) {
// ignore
}
throw ex;
}
}
public static Object getStyle( JComponent c ) {
return c.getClientProperty( FlatClientProperties.STYLE );
}
static PropertyChangeListener createPropertyChangeListener( JComponent c,
Consumer<Object> applyStyle, PropertyChangeListener superListener )
{
return e -> {
if( superListener != null )
superListener.propertyChange( e );
if( FlatClientProperties.STYLE.equals( e.getPropertyName() ) ) {
applyStyle.accept( e.getNewValue() );
c.revalidate();
c.repaint();
}
};
}
static Border cloneBorder( Border border ) {
Class<? extends Border> borderClass = border.getClass();
try {
return borderClass.getDeclaredConstructor().newInstance();
} catch( Exception ex ) {
throw new IllegalArgumentException( "failed to clone border '" + borderClass.getName() + "'" );
}
}
static Icon cloneIcon( Icon icon ) {
Class<? extends Icon> iconClass = icon.getClass();
try {
return iconClass.getDeclaredConstructor().newInstance();
} catch( Exception ex ) {
throw new IllegalArgumentException( "failed to clone icon '" + iconClass.getName() + "'" );
}
}
/**
* Returns a map of all fields annotated with {@link Styleable}.
* The key is the name of the field and the value the type of the field.
*/
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj ) {
return getAnnotatedStyleableInfos( obj, null );
}
public static Map<String, Class<?>> getAnnotatedStyleableInfos( Object obj, Border border ) {
Map<String, Class<?>> infos = new LinkedHashMap<>();
collectAnnotatedStyleableInfos( obj, infos );
collectStyleableInfos( border, infos );
return infos;
}
/**
* Search for all fields annotated with {@link Styleable} and add them to the given map.
* The key is the name of the field and the value the type of the field.
*/
public static void collectAnnotatedStyleableInfos( Object obj, Map<String, Class<?>> infos ) {
Class<?> cls = obj.getClass();
for(;;) {
for( Field f : cls.getDeclaredFields() ) {
if( !isValidField( f ) )
continue;
Styleable styleable = f.getAnnotation( Styleable.class );
if( styleable == null )
continue;
String name = f.getName();
Class<?> type = f.getType();
// handle "dot" keys (e.g. change field name "iconArrowType" to style key "icon.arrowType")
if( styleable.dot() ) {
int len = name.length();
for( int i = 0; i < len; i++ ) {
if( Character.isUpperCase( name.charAt( i ) ) ) {
name = name.substring( 0, i ) + '.'
+ Character.toLowerCase( name.charAt( i ) )
+ name.substring( i + 1 );
break;
}
}
}
// field has a different type
if( styleable.type() != Void.class )
type = styleable.type();
infos.put( name, type );
}
cls = cls.getSuperclass();
if( cls == null )
return;
String superclassName = cls.getName();
if( superclassName.startsWith( "java." ) || superclassName.startsWith( "javax." ) )
return;
}
}
public static void collectStyleableInfos( Border border, Map<String, Class<?>> infos ) {
if( border instanceof StyleableBorder )
infos.putAll( ((StyleableBorder)border).getStyleableInfos() );
}
public static void putAllPrefixKey( Map<String, Class<?>> infos, String keyPrefix, Map<String, Class<?>> infos2 ) {
for( Map.Entry<String, Class<?>> e : infos2.entrySet() )
infos.put( keyPrefix.concat( e.getKey() ), e.getValue() );
}
//---- class UnknownStyleException ----------------------------------------
public static class UnknownStyleException
extends IllegalArgumentException
{
public UnknownStyleException( String key ) {
super( key );
}
@Override
public String getMessage() {
return "unknown style '" + super.getMessage() + "'";
}
}
}

View File

@@ -52,7 +52,9 @@ import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.IntConsumer; import java.util.function.IntConsumer;
@@ -84,6 +86,10 @@ import javax.swing.plaf.basic.BasicTabbedPaneUI;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import javax.swing.text.View; import javax.swing.text.View;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatTabbedPaneCloseIcon;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.Animator; import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.CubicBezierEasing; import com.formdev.flatlaf.util.CubicBezierEasing;
import com.formdev.flatlaf.util.JavaCompatibility; import com.formdev.flatlaf.util.JavaCompatibility;
@@ -101,7 +107,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TabbedPane.font Font * @uiDefault TabbedPane.font Font
* @uiDefault TabbedPane.background Color * @uiDefault TabbedPane.background Color
* @uiDefault TabbedPane.foreground Color * @uiDefault TabbedPane.foreground Color
* @uiDefault TabbedPane.shadow Color used for scroll arrows and cropped line * @uiDefault TabbedPane.shadow Color used for cropped line
* @uiDefault TabbedPane.textIconGap int * @uiDefault TabbedPane.textIconGap int
* @uiDefault TabbedPane.tabInsets Insets * @uiDefault TabbedPane.tabInsets Insets
* @uiDefault TabbedPane.selectedTabPadInsets Insets unused * @uiDefault TabbedPane.selectedTabPadInsets Insets unused
@@ -156,6 +162,7 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatTabbedPaneUI public class FlatTabbedPaneUI
extends BasicTabbedPaneUI extends BasicTabbedPaneUI
implements StyleableUI
{ {
// tabs popup policy / scroll arrows policy // tabs popup policy / scroll arrows policy
protected static final int NEVER = 0; protected static final int NEVER = 0;
@@ -177,43 +184,43 @@ public class FlatTabbedPaneUI
private static Set<KeyStroke> focusBackwardTraversalKeys; private static Set<KeyStroke> focusBackwardTraversalKeys;
protected Color foreground; protected Color foreground;
protected Color disabledForeground; @Styleable protected Color disabledForeground;
protected Color selectedBackground; @Styleable protected Color selectedBackground;
protected Color selectedForeground; @Styleable protected Color selectedForeground;
protected Color underlineColor; @Styleable protected Color underlineColor;
protected Color disabledUnderlineColor; @Styleable protected Color disabledUnderlineColor;
protected Color hoverColor; @Styleable protected Color hoverColor;
protected Color focusColor; @Styleable protected Color focusColor;
protected Color tabSeparatorColor; @Styleable protected Color tabSeparatorColor;
protected Color contentAreaColor; @Styleable protected Color contentAreaColor;
private int textIconGapUnscaled; private int textIconGapUnscaled;
protected int minimumTabWidth; @Styleable protected int minimumTabWidth;
protected int maximumTabWidth; @Styleable protected int maximumTabWidth;
protected int tabHeight; @Styleable protected int tabHeight;
protected int tabSelectionHeight; @Styleable protected int tabSelectionHeight;
protected int contentSeparatorHeight; @Styleable protected int contentSeparatorHeight;
protected boolean showTabSeparators; @Styleable protected boolean showTabSeparators;
protected boolean tabSeparatorsFullHeight; @Styleable protected boolean tabSeparatorsFullHeight;
protected boolean hasFullBorder; @Styleable protected boolean hasFullBorder;
protected boolean tabsOpaque = true; @Styleable protected boolean tabsOpaque = true;
private int tabsPopupPolicy; @Styleable(type=String.class) private int tabsPopupPolicy;
private int scrollButtonsPolicy; @Styleable(type=String.class) private int scrollButtonsPolicy;
private int scrollButtonsPlacement; @Styleable(type=String.class) private int scrollButtonsPlacement;
private int tabAreaAlignment; @Styleable(type=String.class) private int tabAreaAlignment;
private int tabAlignment; @Styleable(type=String.class) private int tabAlignment;
private int tabWidthMode; @Styleable(type=String.class) private int tabWidthMode;
protected Icon closeIcon; protected Icon closeIcon;
protected String arrowType; @Styleable protected String arrowType;
protected Insets buttonInsets; @Styleable protected Insets buttonInsets;
protected int buttonArc; @Styleable protected int buttonArc;
protected Color buttonHoverBackground; @Styleable protected Color buttonHoverBackground;
protected Color buttonPressedBackground; @Styleable protected Color buttonPressedBackground;
protected String moreTabsButtonToolTipText; @Styleable protected String moreTabsButtonToolTipText;
protected JViewport tabViewport; protected JViewport tabViewport;
protected FlatWheelTabScroller wheelTabScroller; protected FlatWheelTabScroller wheelTabScroller;
@@ -231,6 +238,8 @@ public class FlatTabbedPaneUI
private boolean pressedTabClose; private boolean pressedTabClose;
private Object[] oldRenderingHints; private Object[] oldRenderingHints;
private Map<String, Object> oldStyleValues;
private boolean closeIconShared = true;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTabbedPaneUI(); return new FlatTabbedPaneUI();
@@ -259,6 +268,8 @@ public class FlatTabbedPaneUI
buttonPressedBackground = UIManager.getColor( "TabbedPane.buttonPressedBackground" ); buttonPressedBackground = UIManager.getColor( "TabbedPane.buttonPressedBackground" );
super.installUI( c ); super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -313,6 +324,7 @@ public class FlatTabbedPaneUI
tabAlignment = parseAlignment( UIManager.getString( "TabbedPane.tabAlignment" ), CENTER ); tabAlignment = parseAlignment( UIManager.getString( "TabbedPane.tabAlignment" ), CENTER );
tabWidthMode = parseTabWidthMode( UIManager.getString( "TabbedPane.tabWidthMode" ) ); tabWidthMode = parseTabWidthMode( UIManager.getString( "TabbedPane.tabWidthMode" ) );
closeIcon = UIManager.getIcon( "TabbedPane.closeIcon" ); closeIcon = UIManager.getIcon( "TabbedPane.closeIcon" );
closeIconShared = true;
buttonInsets = UIManager.getInsets( "TabbedPane.buttonInsets" ); buttonInsets = UIManager.getInsets( "TabbedPane.buttonInsets" );
buttonArc = UIManager.getInt( "TabbedPane.buttonArc" ); buttonArc = UIManager.getInt( "TabbedPane.buttonArc" );
@@ -361,6 +373,8 @@ public class FlatTabbedPaneUI
buttonHoverBackground = null; buttonHoverBackground = null;
buttonPressedBackground = null; buttonPressedBackground = null;
oldStyleValues = null;
MigLayoutVisualPadding.uninstall( tabPane ); MigLayoutVisualPadding.uninstall( tabPane );
} }
@@ -558,6 +572,78 @@ public class FlatTabbedPaneUI
return new FlatScrollableTabButton( direction ); return new FlatScrollableTabButton( direction );
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
// update buttons
for( Component c : tabPane.getComponents() ) {
if( c instanceof FlatTabAreaButton )
((FlatTabAreaButton)c).updateStyle();
}
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
// close icon
if( key.startsWith( "close" ) ) {
if( !(closeIcon instanceof FlatTabbedPaneCloseIcon) )
return new UnknownStyleException( key );
if( closeIconShared ) {
closeIcon = FlatStylingSupport.cloneIcon( closeIcon );
closeIconShared = false;
}
return ((FlatTabbedPaneCloseIcon)closeIcon).applyStyleProperty( key, value );
}
if( value instanceof String ) {
switch( key ) {
case "tabsPopupPolicy": value = parseTabsPopupPolicy( (String) value ); break;
case "scrollButtonsPolicy": value = parseScrollButtonsPolicy( (String) value ); break;
case "scrollButtonsPlacement": value = parseScrollButtonsPlacement( (String) value ); break;
case "tabAreaAlignment": value = parseAlignment( (String) value, LEADING ); break;
case "tabAlignment": value = parseAlignment( (String) value, CENTER ); break;
case "tabWidthMode": value = parseTabWidthMode( (String) value ); break;
}
} else {
Object oldValue = null;
switch( key ) {
// BasicTabbedPaneUI
case "tabInsets": oldValue = tabInsets; tabInsets = (Insets) value; return oldValue;
case "tabAreaInsets": oldValue = tabAreaInsets; tabAreaInsets = (Insets) value; return oldValue;
case "textIconGap":
oldValue = textIconGapUnscaled;
textIconGapUnscaled = (int) value;
textIconGap = scale( textIconGapUnscaled );
return oldValue;
}
}
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, tabPane, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = new LinkedHashMap<>();
infos.put( "tabInsets", Insets.class );
infos.put( "tabAreaInsets", Insets.class );
infos.put( "textIconGap", int.class );
FlatStylingSupport.collectAnnotatedStyleableInfos( this, infos );
if( closeIcon instanceof FlatTabbedPaneCloseIcon )
infos.putAll( ((FlatTabbedPaneCloseIcon)closeIcon).getStyleableInfos() );
return infos;
}
protected void setRolloverTab( int x, int y ) { protected void setRolloverTab( int x, int y ) {
setRolloverTab( tabForCoordinate( tabPane, x, y ) ); setRolloverTab( tabForCoordinate( tabPane, x, y ) );
} }
@@ -1567,6 +1653,12 @@ public class FlatTabbedPaneUI
setArrowWidth( 10 ); setArrowWidth( 10 );
} }
protected void updateStyle() {
updateStyle( arrowType,
FlatTabbedPaneUI.this.foreground, FlatTabbedPaneUI.this.disabledForeground,
null, buttonHoverBackground, null, buttonPressedBackground );
}
@Override @Override
protected Color deriveBackground( Color background ) { protected Color deriveBackground( Color background ) {
return FlatUIUtils.deriveColor( background, tabPane.getBackground() ); return FlatUIUtils.deriveColor( background, tabPane.getBackground() );
@@ -2351,6 +2443,12 @@ public class FlatTabbedPaneUI
tabPane.repaint(); tabPane.repaint();
ensureSelectedTabIsVisibleLater(); ensureSelectedTabIsVisibleLater();
break; break;
case STYLE:
applyStyle( e.getNewValue() );
tabPane.revalidate();
tabPane.repaint();
break;
} }
} }

View File

@@ -16,11 +16,15 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Insets;
import java.util.function.Function;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.TableUI;
/** /**
* Cell border for {@link javax.swing.table.DefaultTableCellRenderer} * Cell border for {@link javax.swing.table.DefaultTableCellRenderer}
@@ -33,12 +37,54 @@ import javax.swing.UIManager;
public class FlatTableCellBorder public class FlatTableCellBorder
extends FlatLineBorder extends FlatLineBorder
{ {
final boolean showCellFocusIndicator = UIManager.getBoolean( "Table.showCellFocusIndicator" ); protected boolean showCellFocusIndicator = UIManager.getBoolean( "Table.showCellFocusIndicator" );
private Component c;
protected FlatTableCellBorder() { protected FlatTableCellBorder() {
super( UIManager.getInsets( "Table.cellMargins" ), UIManager.getColor( "Table.cellFocusColor" ) ); super( UIManager.getInsets( "Table.cellMargins" ), UIManager.getColor( "Table.cellFocusColor" ) );
} }
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
Insets m = getStyleFromTableUI( c, ui -> ui.cellMargins );
if( m != null )
return scaleInsets( c, insets, m.top, m.left, m.bottom, m.right );
return super.getBorderInsets( c, insets );
}
@Override
public Color getLineColor() {
if( c != null ) {
Color color = getStyleFromTableUI( c, ui -> ui.cellFocusColor );
if( color != null )
return color;
}
return super.getLineColor();
}
@Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
this.c = c;
super.paintBorder( c, g, x, y, width, height );
this.c = null;
}
/**
* Because this borders are always shared for all tables,
* get border specific style from FlatTableUI.
*/
static <T> T getStyleFromTableUI( Component c, Function<FlatTableUI, T> f ) {
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
if( table != null ) {
TableUI ui = table.getUI();
if( ui instanceof FlatTableUI )
return f.apply( (FlatTableUI) ui );
}
return null;
}
//---- class Default ------------------------------------------------------ //---- class Default ------------------------------------------------------
/** /**
@@ -74,6 +120,9 @@ public class FlatTableCellBorder
{ {
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator );
boolean showCellFocusIndicator = (b != null) ? b : this.showCellFocusIndicator;
if( !showCellFocusIndicator ) { if( !showCellFocusIndicator ) {
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c ); JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
if( table != null && !isSelectionEditable( table ) ) if( table != null && !isSelectionEditable( table ) )

View File

@@ -21,6 +21,7 @@ import java.awt.Component;
import java.awt.Container; import java.awt.Container;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import javax.swing.JScrollBar; import javax.swing.JScrollBar;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
@@ -51,12 +52,30 @@ public class FlatTableHeaderBorder
super( UIManager.getInsets( "TableHeader.cellMargins" ) ); super( UIManager.getInsets( "TableHeader.cellMargins" ) );
} }
@Override
public Insets getBorderInsets( Component c, Insets insets ) {
JTableHeader header = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
if( header != null ) {
if( header.getUI() instanceof FlatTableHeaderUI ) {
FlatTableHeaderUI ui = (FlatTableHeaderUI) header.getUI();
if( ui.cellMargins != null ) {
Insets m = ui.cellMargins;
return scaleInsets( c, insets, m.top, m.left, m.bottom, m.right );
}
}
}
return super.getBorderInsets( c, insets );
}
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
JTableHeader header = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c ); JTableHeader header = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c );
boolean leftToRight = (header != null ? header : c).getComponentOrientation().isLeftToRight(); boolean leftToRight = (header != null ? header : c).getComponentOrientation().isLeftToRight();
boolean paintLeft = !leftToRight; boolean paintLeft = !leftToRight;
boolean paintRight = leftToRight; boolean paintRight = leftToRight;
Color separatorColor = this.separatorColor;
Color bottomSeparatorColor = this.bottomSeparatorColor;
if( header != null ) { if( header != null ) {
int hx = SwingUtilities.convertPoint( c, x, y, header ).x; int hx = SwingUtilities.convertPoint( c, x, y, header ).x;
@@ -68,6 +87,16 @@ public class FlatTableHeaderBorder
if( hx + width >= header.getWidth() && leftToRight && hideTrailingVerticalLine( header ) ) if( hx + width >= header.getWidth() && leftToRight && hideTrailingVerticalLine( header ) )
paintRight = false; paintRight = false;
} }
// Because this border is always shared for all table headers,
// get border specific style from FlatTableHeaderUI.
if( header.getUI() instanceof FlatTableHeaderUI ) {
FlatTableHeaderUI ui = (FlatTableHeaderUI) header.getUI();
if( ui.separatorColor != null )
separatorColor = ui.separatorColor;
if( ui.bottomSeparatorColor != null )
bottomSeparatorColor = ui.bottomSeparatorColor;
}
} }
float lineWidth = UIScale.scale( 1f ); float lineWidth = UIScale.scale( 1f );
@@ -110,6 +139,12 @@ public class FlatTableHeaderBorder
} }
protected boolean hideTrailingVerticalLine( JTableHeader header ) { protected boolean hideTrailingVerticalLine( JTableHeader header ) {
if( header.getUI() instanceof FlatTableHeaderUI ) {
FlatTableHeaderUI ui = (FlatTableHeaderUI) header.getUI();
if( ui.showTrailingVerticalLine )
return false;
}
if( showTrailingVerticalLine ) if( showTrailingVerticalLine )
return false; return false;

View File

@@ -26,7 +26,8 @@ import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.util.Objects; import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLabel; import javax.swing.JLabel;
@@ -40,6 +41,9 @@ import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTableHeaderUI; import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.TableCellRenderer; import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -64,32 +68,52 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TableHeader.bottomSeparatorColor Color * @uiDefault TableHeader.bottomSeparatorColor Color
* @uiDefault TableHeader.showTrailingVerticalLine boolean * @uiDefault TableHeader.showTrailingVerticalLine boolean
* *
* <!-- FlatAscendingSortIcon and FlatDescendingSortIcon -->
*
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Table.sortIconColor Color
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatTableHeaderUI public class FlatTableHeaderUI
extends BasicTableHeaderUI extends BasicTableHeaderUI
implements StyleableUI
{ {
protected Color bottomSeparatorColor; @Styleable protected Color bottomSeparatorColor;
protected int height; @Styleable protected int height;
protected int sortIconPosition; @Styleable(type=String.class) protected int sortIconPosition;
// for FlatTableHeaderBorder
@Styleable protected Insets cellMargins;
@Styleable protected Color separatorColor;
/** @since 2 */ @Styleable protected boolean showTrailingVerticalLine;
// for FlatAscendingSortIcon and FlatDescendingSortIcon
// (needs to be public because icon classes are in another package)
@Styleable public String arrowType;
@Styleable public Color sortIconColor;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTableHeaderUI(); return new FlatTableHeaderUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" ); bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" );
height = UIManager.getInt( "TableHeader.height" ); height = UIManager.getInt( "TableHeader.height" );
switch( Objects.toString( UIManager.getString( "TableHeader.sortIconPosition" ), "right" ) ) { sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) );
default:
case "right": sortIconPosition = SwingConstants.RIGHT; break;
case "left": sortIconPosition = SwingConstants.LEFT; break;
case "top": sortIconPosition = SwingConstants.TOP; break;
case "bottom": sortIconPosition = SwingConstants.BOTTOM; break;
}
} }
@Override @Override
@@ -97,6 +121,62 @@ public class FlatTableHeaderUI
super.uninstallDefaults(); super.uninstallDefaults();
bottomSeparatorColor = null; bottomSeparatorColor = null;
oldStyleValues = null;
}
@Override
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( header, this::applyStyle, null );
header.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
header.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = null;
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
if( key.equals( "sortIconPosition" ) && value instanceof String )
value = parseSortIconPosition( (String) value );
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, header, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
private static int parseSortIconPosition( String str ) {
if( str == null )
str = "";
switch( str ) {
default:
case "right": return SwingConstants.RIGHT;
case "left": return SwingConstants.LEFT;
case "top": return SwingConstants.TOP;
case "bottom": return SwingConstants.BOTTOM;
}
} }
@Override @Override

View File

@@ -22,10 +22,12 @@ import java.awt.Dimension;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JViewport; import javax.swing.JViewport;
@@ -36,6 +38,8 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTableUI; import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.table.JTableHeader; import javax.swing.table.JTableHeader;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.Graphics2DProxy; import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -90,27 +94,41 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatTableUI public class FlatTableUI
extends BasicTableUI extends BasicTableUI
implements StyleableUI
{ {
protected boolean showHorizontalLines; protected boolean showHorizontalLines;
protected boolean showVerticalLines; protected boolean showVerticalLines;
/** @since 1.6 */ protected boolean showTrailingVerticalLine; /** @since 1.6 */ @Styleable protected boolean showTrailingVerticalLine;
protected Dimension intercellSpacing; protected Dimension intercellSpacing;
protected Color selectionBackground; @Styleable protected Color selectionBackground;
protected Color selectionForeground; @Styleable protected Color selectionForeground;
protected Color selectionInactiveBackground; @Styleable protected Color selectionInactiveBackground;
protected Color selectionInactiveForeground; @Styleable protected Color selectionInactiveForeground;
// for FlatTableCellBorder
@Styleable protected Insets cellMargins;
@Styleable protected Color cellFocusColor;
@Styleable protected boolean showCellFocusIndicator;
private boolean oldShowHorizontalLines; private boolean oldShowHorizontalLines;
private boolean oldShowVerticalLines; private boolean oldShowVerticalLines;
private Dimension oldIntercellSpacing; private Dimension oldIntercellSpacing;
private PropertyChangeListener propertyChangeListener; private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTableUI(); return new FlatTableUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -155,6 +173,8 @@ public class FlatTableUI
selectionInactiveBackground = null; selectionInactiveBackground = null;
selectionInactiveForeground = null; selectionInactiveForeground = null;
oldStyleValues = null;
// restore old show horizontal/vertical lines (if not modified) // restore old show horizontal/vertical lines (if not modified)
if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() ) if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() )
table.setShowHorizontalLines( true ); table.setShowHorizontalLines( true );
@@ -171,8 +191,17 @@ public class FlatTableUI
super.installListeners(); super.installListeners();
propertyChangeListener = e -> { propertyChangeListener = e -> {
if( FlatClientProperties.COMPONENT_FOCUS_OWNER.equals( e.getPropertyName() ) ) switch( e.getPropertyName() ) {
toggleSelectionColors(); case FlatClientProperties.COMPONENT_FOCUS_OWNER:
toggleSelectionColors();
break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
table.revalidate();
table.repaint();
break;
}
}; };
table.addPropertyChangeListener( propertyChangeListener ); table.addPropertyChangeListener( propertyChangeListener );
} }
@@ -206,6 +235,51 @@ public class FlatTableUI
}; };
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
Color oldSelectionBackground = selectionBackground;
Color oldSelectionForeground = selectionForeground;
Color oldSelectionInactiveBackground = selectionInactiveBackground;
Color oldSelectionInactiveForeground = selectionInactiveForeground;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
// update selection background
if( selectionBackground != oldSelectionBackground ) {
Color selBg = table.getSelectionBackground();
if( selBg == oldSelectionBackground )
table.setSelectionBackground( selectionBackground );
else if( selBg == oldSelectionInactiveBackground )
table.setSelectionBackground( selectionInactiveBackground );
}
// update selection foreground
if( selectionForeground != oldSelectionForeground ) {
Color selFg = table.getSelectionForeground();
if( selFg == oldSelectionForeground )
table.setSelectionForeground( selectionForeground );
else if( selFg == oldSelectionInactiveForeground )
table.setSelectionForeground( selectionInactiveForeground );
}
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, table, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
/** /**
* Toggle selection colors from focused to inactive and vice versa. * Toggle selection colors from focused to inactive and vice versa.
* *

View File

@@ -23,13 +23,14 @@ import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Map;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextAreaUI; import javax.swing.plaf.basic.BasicTextAreaUI;
import javax.swing.text.JTextComponent; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
@@ -60,17 +61,22 @@ import com.formdev.flatlaf.util.HiDPIUtils;
*/ */
public class FlatTextAreaUI public class FlatTextAreaUI
extends BasicTextAreaUI extends BasicTextAreaUI
implements StyleableUI
{ {
protected int minimumWidth; @Styleable protected int minimumWidth;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color background; private Color background;
protected Color disabledBackground; @Styleable protected Color disabledBackground;
protected Color inactiveBackground; @Styleable protected Color inactiveBackground;
protected Color focusedBackground; @Styleable protected Color focusedBackground;
private Color oldDisabledBackground;
private Color oldInactiveBackground;
private Insets defaultMargin; private Insets defaultMargin;
private FocusListener focusListener; private FocusListener focusListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTextAreaUI(); return new FlatTextAreaUI();
@@ -80,7 +86,7 @@ public class FlatTextAreaUI
public void installUI( JComponent c ) { public void installUI( JComponent c ) {
super.installUI( c ); super.installUI( c );
updateBackground(); applyStyle( FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -105,6 +111,11 @@ public class FlatTextAreaUI
disabledBackground = null; disabledBackground = null;
inactiveBackground = null; inactiveBackground = null;
focusedBackground = null; focusedBackground = null;
oldDisabledBackground = null;
oldInactiveBackground = null;
oldStyleValues = null;
} }
@Override @Override
@@ -126,38 +137,46 @@ public class FlatTextAreaUI
@Override @Override
protected void propertyChange( PropertyChangeEvent e ) { protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e ); // invoke updateBackground() before super.propertyChange()
FlatEditorPaneUI.propertyChange( getComponent(), e ); String propertyName = e.getPropertyName();
if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
updateBackground();
switch( e.getPropertyName() ) { super.propertyChange( e );
case "editable": FlatEditorPaneUI.propertyChange( getComponent(), e, this::applyStyle );
case "enabled": }
updateBackground();
break; /**
} * @since 2
*/
protected void applyStyle( Object style ) {
oldDisabledBackground = disabledBackground;
oldInactiveBackground = inactiveBackground;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
updateBackground();
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, getComponent(), key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
private void updateBackground() { private void updateBackground() {
JTextComponent c = getComponent(); FlatTextFieldUI.updateBackground( getComponent(), background,
disabledBackground, inactiveBackground,
Color background = c.getBackground(); oldDisabledBackground, oldInactiveBackground );
if( !(background instanceof UIResource) )
return;
// do not update background if it currently has a unknown color (assigned from outside)
if( background != this.background &&
background != disabledBackground &&
background != inactiveBackground )
return;
Color newBackground = !c.isEnabled()
? disabledBackground
: (!c.isEditable()
? inactiveBackground
: this.background);
if( newBackground != background )
c.setBackground( newBackground );
} }
@Override @Override

View File

@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Component; import java.awt.Component;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
/** /**
* Border for various text components (e.g. {@link javax.swing.JTextField}). * Border for various text components (e.g. {@link javax.swing.JTextField}).
@@ -29,7 +30,7 @@ import javax.swing.UIManager;
public class FlatTextBorder public class FlatTextBorder
extends FlatBorder extends FlatBorder
{ {
protected final int arc = UIManager.getInt( "TextComponent.arc" ); @Styleable protected int arc = UIManager.getInt( "TextComponent.arc" );
@Override @Override
protected int getArc( Component c ) { protected int getArc( Component c ) {

View File

@@ -27,7 +27,10 @@ import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSpinner; import javax.swing.JSpinner;
@@ -40,6 +43,8 @@ import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.Caret; import javax.swing.text.Caret;
import javax.swing.text.JTextComponent; import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.JavaCompatibility; import com.formdev.flatlaf.util.JavaCompatibility;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -75,20 +80,36 @@ import com.formdev.flatlaf.util.UIScale;
*/ */
public class FlatTextFieldUI public class FlatTextFieldUI
extends BasicTextFieldUI extends BasicTextFieldUI
implements StyleableUI
{ {
protected int minimumWidth; @Styleable protected int minimumWidth;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color placeholderForeground; private Color background;
protected Color focusedBackground; @Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground;
@Styleable protected Color placeholderForeground;
@Styleable protected Color focusedBackground;
private Color oldDisabledBackground;
private Color oldInactiveBackground;
private Insets defaultMargin; private Insets defaultMargin;
private FocusListener focusListener; private FocusListener focusListener;
private Map<String, Object> oldStyleValues;
private AtomicBoolean borderShared;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTextFieldUI(); return new FlatTextFieldUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -96,6 +117,9 @@ public class FlatTextFieldUI
String prefix = getPropertyPrefix(); String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( prefix + ".background" );
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" ); placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
@@ -110,9 +134,18 @@ public class FlatTextFieldUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
background = null;
disabledBackground = null;
inactiveBackground = null;
placeholderForeground = null; placeholderForeground = null;
focusedBackground = null; focusedBackground = null;
oldDisabledBackground = null;
oldInactiveBackground = null;
oldStyleValues = null;
borderShared = null;
MigLayoutVisualPadding.uninstall( getComponent() ); MigLayoutVisualPadding.uninstall( getComponent() );
} }
@@ -141,11 +174,15 @@ public class FlatTextFieldUI
@Override @Override
protected void propertyChange( PropertyChangeEvent e ) { protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e ); String propertyName = e.getPropertyName();
propertyChange( getComponent(), e ); if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
updateBackground();
else
super.propertyChange( e );
propertyChange( getComponent(), e, this::applyStyle );
} }
static void propertyChange( JTextComponent c, PropertyChangeEvent e ) { static void propertyChange( JTextComponent c, PropertyChangeEvent e, Consumer<Object> applyStyle ) {
switch( e.getPropertyName() ) { switch( e.getPropertyName() ) {
case FlatClientProperties.PLACEHOLDER_TEXT: case FlatClientProperties.PLACEHOLDER_TEXT:
case FlatClientProperties.COMPONENT_ROUND_RECT: case FlatClientProperties.COMPONENT_ROUND_RECT:
@@ -156,9 +193,77 @@ public class FlatTextFieldUI
case FlatClientProperties.MINIMUM_WIDTH: case FlatClientProperties.MINIMUM_WIDTH:
c.revalidate(); c.revalidate();
break; break;
case FlatClientProperties.STYLE:
applyStyle.accept( e.getNewValue() );
c.revalidate();
c.repaint();
break;
} }
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldDisabledBackground = disabledBackground;
oldInactiveBackground = inactiveBackground;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
updateBackground();
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
if( borderShared == null )
borderShared = new AtomicBoolean( true );
return FlatStylingSupport.applyToAnnotatedObjectOrBorder( this, key, value, getComponent(), borderShared );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this, getComponent().getBorder() );
}
private void updateBackground() {
updateBackground( getComponent(), background,
disabledBackground, inactiveBackground,
oldDisabledBackground, oldInactiveBackground );
}
// same functionality as BasicTextUI.updateBackground()
static void updateBackground( JTextComponent c, Color background,
Color disabledBackground, Color inactiveBackground,
Color oldDisabledBackground, Color oldInactiveBackground )
{
Color oldBackground = c.getBackground();
if( !(oldBackground instanceof UIResource) )
return;
// do not update background if it currently has a unknown color (assigned from outside)
if( oldBackground != background &&
oldBackground != disabledBackground &&
oldBackground != inactiveBackground &&
oldBackground != oldDisabledBackground &&
oldBackground != oldInactiveBackground )
return;
Color newBackground = !c.isEnabled()
? disabledBackground
: (!c.isEditable()
? inactiveBackground
: background);
if( newBackground != oldBackground )
c.setBackground( newBackground );
}
@Override @Override
protected void paintSafely( Graphics g ) { protected void paintSafely( Graphics g ) {
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground ); paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );

View File

@@ -23,11 +23,14 @@ import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Map;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JEditorPane; import javax.swing.JEditorPane;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTextPaneUI; import javax.swing.plaf.basic.BasicTextPaneUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
@@ -58,20 +61,35 @@ import com.formdev.flatlaf.util.HiDPIUtils;
*/ */
public class FlatTextPaneUI public class FlatTextPaneUI
extends BasicTextPaneUI extends BasicTextPaneUI
implements StyleableUI
{ {
protected int minimumWidth; @Styleable protected int minimumWidth;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color focusedBackground; private Color background;
@Styleable protected Color disabledBackground;
@Styleable protected Color inactiveBackground;
@Styleable protected Color focusedBackground;
private Color oldDisabledBackground;
private Color oldInactiveBackground;
private Insets defaultMargin; private Insets defaultMargin;
private Object oldHonorDisplayProperties; private Object oldHonorDisplayProperties;
private FocusListener focusListener; private FocusListener focusListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTextPaneUI(); return new FlatTextPaneUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -79,6 +97,9 @@ public class FlatTextPaneUI
String prefix = getPropertyPrefix(); String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
background = UIManager.getColor( prefix + ".background" );
disabledBackground = UIManager.getColor( prefix + ".disabledBackground" );
inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
defaultMargin = UIManager.getInsets( prefix + ".margin" ); defaultMargin = UIManager.getInsets( prefix + ".margin" );
@@ -92,8 +113,16 @@ public class FlatTextPaneUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
background = null;
disabledBackground = null;
inactiveBackground = null;
focusedBackground = null; focusedBackground = null;
oldDisabledBackground = null;
oldInactiveBackground = null;
oldStyleValues = null;
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties ); getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
} }
@@ -116,8 +145,46 @@ public class FlatTextPaneUI
@Override @Override
protected void propertyChange( PropertyChangeEvent e ) { protected void propertyChange( PropertyChangeEvent e ) {
// invoke updateBackground() before super.propertyChange()
String propertyName = e.getPropertyName();
if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) )
updateBackground();
super.propertyChange( e ); super.propertyChange( e );
FlatEditorPaneUI.propertyChange( getComponent(), e ); FlatEditorPaneUI.propertyChange( getComponent(), e, this::applyStyle );
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldDisabledBackground = disabledBackground;
oldInactiveBackground = inactiveBackground;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
updateBackground();
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, getComponent(), key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
private void updateBackground() {
FlatTextFieldUI.updateBackground( getComponent(), background,
disabledBackground, inactiveBackground,
oldDisabledBackground, oldInactiveBackground );
} }
@Override @Override

View File

@@ -877,6 +877,10 @@ debug*/
protected class FlatTitleLabelUI protected class FlatTitleLabelUI
extends FlatLabelUI extends FlatLabelUI
{ {
protected FlatTitleLabelUI() {
super( false );
}
@Override @Override
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) { protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) {
boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ); boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() );

View File

@@ -21,11 +21,15 @@ import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Graphics; import java.awt.Graphics;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.util.Iterator;
import java.util.Map;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JToggleButton; import javax.swing.JToggleButton;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.UnknownStyleException;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -73,17 +77,23 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatToggleButtonUI public class FlatToggleButtonUI
extends FlatButtonUI extends FlatButtonUI
{ {
protected int tabUnderlineHeight; @Styleable(dot=true) protected int tabUnderlineHeight;
protected Color tabUnderlineColor; @Styleable(dot=true) protected Color tabUnderlineColor;
protected Color tabDisabledUnderlineColor; @Styleable(dot=true) protected Color tabDisabledUnderlineColor;
protected Color tabSelectedBackground; @Styleable(dot=true) protected Color tabSelectedBackground;
protected Color tabHoverBackground; @Styleable(dot=true) protected Color tabHoverBackground;
protected Color tabFocusBackground; @Styleable(dot=true) protected Color tabFocusBackground;
private boolean defaults_initialized = false; private boolean defaults_initialized = false;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatToggleButtonUI.class, FlatToggleButtonUI::new ); return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatToggleButtonUI.class, () -> new FlatToggleButtonUI( true ) )
: new FlatToggleButtonUI( false );
}
protected FlatToggleButtonUI( boolean shared ) {
super( shared );
} }
@Override @Override
@@ -136,6 +146,31 @@ public class FlatToggleButtonUI
} }
} }
/**
* @since 2
*/
@Override
protected Object applyStyleProperty( AbstractButton b, String key, Object value ) {
if( key.startsWith( "help." ) )
throw new UnknownStyleException( key );
return super.applyStyleProperty( b, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
Map<String, Class<?>> infos = super.getStyleableInfos( c );
Iterator<String> it = infos.keySet().iterator();
while( it.hasNext() ) {
if( it.next().startsWith( "help." ) )
it.remove();
}
return infos;
}
static boolean isTabButton( Component c ) { static boolean isTabButton( Component c ) {
return c instanceof JToggleButton && clientPropertyEquals( (JToggleButton) c, BUTTON_TYPE, BUTTON_TYPE_TAB ); return c instanceof JToggleButton && clientPropertyEquals( (JToggleButton) c, BUTTON_TYPE, BUTTON_TYPE_TAB );
} }

View File

@@ -22,9 +22,11 @@ import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.util.function.Function;
import javax.swing.JToolBar; import javax.swing.JToolBar;
import javax.swing.SwingConstants; import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ToolBarUI;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -42,7 +44,7 @@ public class FlatToolBarBorder
private static final int DOT_SIZE = 2; private static final int DOT_SIZE = 2;
private static final int GRIP_SIZE = DOT_SIZE * 3; private static final int GRIP_SIZE = DOT_SIZE * 3;
protected final Color gripColor = UIManager.getColor( "ToolBar.gripColor" ); protected Color gripColor = UIManager.getColor( "ToolBar.gripColor" );
public FlatToolBarBorder() { public FlatToolBarBorder() {
super( UIManager.getInsets( "ToolBar.borderMargins" ) ); super( UIManager.getInsets( "ToolBar.borderMargins" ) );
@@ -56,7 +58,8 @@ public class FlatToolBarBorder
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
g2.setColor( gripColor ); Color color = getStyleFromToolBarUI( c, ui -> ui.gripColor );
g2.setColor( (color != null) ? color : gripColor );
paintGrip( c, g2, x, y, width, height ); paintGrip( c, g2, x, y, width, height );
} finally { } finally {
g2.dispose(); g2.dispose();
@@ -90,7 +93,14 @@ public class FlatToolBarBorder
@Override @Override
public Insets getBorderInsets( Component c, Insets insets ) { public Insets getBorderInsets( Component c, Insets insets ) {
insets = super.getBorderInsets( c, insets ); Insets m = getStyleFromToolBarUI( c, ui -> ui.borderMargins );
if( m != null ) {
int t = top, l = left, b = bottom, r = right;
top = m.top; left = m.left; bottom = m.bottom; right = m.right;
insets = super.getBorderInsets( c, insets );
top = t; left = l; bottom = b; right = r;
} else
insets = super.getBorderInsets( c, insets );
// add grip inset if floatable // add grip inset if floatable
if( c instanceof JToolBar && ((JToolBar)c).isFloatable() ) { if( c instanceof JToolBar && ((JToolBar)c).isFloatable() ) {
@@ -106,4 +116,17 @@ public class FlatToolBarBorder
return insets; return insets;
} }
/**
* Because this border is shared for all toolbars,
* get border specific style from FlatToolBarUI.
*/
static <T> T getStyleFromToolBarUI( Component c, Function<FlatToolBarUI, T> f ) {
if( c instanceof JToolBar ) {
ToolBarUI ui = ((JToolBar)c).getUI();
if( ui instanceof FlatToolBarUI )
return f.apply( (FlatToolBarUI) ui );
}
return null;
}
} }

View File

@@ -22,6 +22,8 @@ import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSeparator; import javax.swing.JSeparator;
import javax.swing.JToolBar; import javax.swing.JToolBar;
@@ -29,6 +31,9 @@ import javax.swing.SwingConstants;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicToolBarSeparatorUI; import javax.swing.plaf.basic.BasicToolBarSeparatorUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar.Separator}. * Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar.Separator}.
@@ -42,16 +47,36 @@ import javax.swing.plaf.basic.BasicToolBarSeparatorUI;
*/ */
public class FlatToolBarSeparatorUI public class FlatToolBarSeparatorUI
extends BasicToolBarSeparatorUI extends BasicToolBarSeparatorUI
implements StyleableUI
{ {
private static final int LINE_WIDTH = 1; private static final int LINE_WIDTH = 1;
protected int separatorWidth; @Styleable protected int separatorWidth;
protected Color separatorColor; @Styleable protected Color separatorColor;
private final boolean shared;
private boolean defaults_initialized = false; private boolean defaults_initialized = false;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return FlatUIUtils.createSharedUI( FlatToolBarSeparatorUI.class, FlatToolBarSeparatorUI::new ); return FlatUIUtils.canUseSharedUI( c )
? FlatUIUtils.createSharedUI( FlatToolBarSeparatorUI.class, () -> new FlatToolBarSeparatorUI( true ) )
: new FlatToolBarSeparatorUI( false );
}
/**
* @since 2
*/
protected FlatToolBarSeparatorUI( boolean shared ) {
this.shared = shared;
}
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -73,7 +98,59 @@ public class FlatToolBarSeparatorUI
@Override @Override
protected void uninstallDefaults( JSeparator s ) { protected void uninstallDefaults( JSeparator s ) {
super.uninstallDefaults( s ); super.uninstallDefaults( s );
defaults_initialized = false; defaults_initialized = false;
oldStyleValues = null;
}
@Override
protected void installListeners( JSeparator s ) {
super.installListeners( s );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
s, style -> applyStyle( s, this, style ), null );
s.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
}
@Override
protected void uninstallListeners( JSeparator s ) {
super.uninstallListeners( s );
s.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = null;
}
private static void applyStyle( JSeparator s, FlatToolBarSeparatorUI ui, Object style ) {
if( style != null && ui.shared ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
s.updateUI();
} else
ui.applyStyle( style );
s.revalidate();
s.repaint();
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObject( this, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
} }
@Override @Override

View File

@@ -16,16 +16,21 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Insets; import java.awt.Insets;
import java.awt.event.ContainerEvent; import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener; import java.awt.event.ContainerListener;
import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.AbstractButton; import javax.swing.AbstractButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicToolBarUI; import javax.swing.plaf.basic.BasicToolBarUI;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/** /**
* Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar}. * Provides the Flat LaF UI delegate for {@link javax.swing.JToolBar}.
@@ -46,13 +51,25 @@ import javax.swing.plaf.basic.BasicToolBarUI;
* *
* @uiDefault ToolBar.focusableButtons boolean * @uiDefault ToolBar.focusableButtons boolean
* *
* <!-- FlatToolBarBorder -->
*
* @uiDefault ToolBar.borderMargins Insets
* @uiDefault ToolBar.gripColor Color
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatToolBarUI public class FlatToolBarUI
extends BasicToolBarUI extends BasicToolBarUI
implements StyleableUI
{ {
/** @since 1.4 */ /** @since 1.4 */
protected boolean focusableButtons; @Styleable protected boolean focusableButtons;
// for FlatToolBarBorder
@Styleable protected Insets borderMargins;
@Styleable protected Color gripColor;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatToolBarUI(); return new FlatToolBarUI();
@@ -65,6 +82,8 @@ public class FlatToolBarUI
// disable focusable state of buttons (when switching from another Laf) // disable focusable state of buttons (when switching from another Laf)
if( !focusableButtons ) if( !focusableButtons )
setButtonsFocusable( false ); setButtonsFocusable( false );
applyStyle( FlatStylingSupport.getStyle( c ) );
} }
@Override @Override
@@ -74,6 +93,8 @@ public class FlatToolBarUI
// re-enable focusable state of buttons (when switching to another Laf) // re-enable focusable state of buttons (when switching to another Laf)
if( !focusableButtons ) if( !focusableButtons )
setButtonsFocusable( true ); setButtonsFocusable( true );
oldStyleValues = null;
} }
@Override @Override
@@ -110,6 +131,38 @@ public class FlatToolBarUI
}; };
} }
@Override
protected PropertyChangeListener createPropertyListener() {
return FlatStylingSupport.createPropertyChangeListener( toolBar, this::applyStyle, super.createPropertyListener() );
}
/**
* @since 2
*/
protected void applyStyle( Object style ) {
boolean oldFocusableButtons = focusableButtons;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
if( focusableButtons != oldFocusableButtons )
setButtonsFocusable( focusableButtons );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, toolBar, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
/** /**
* @since 1.4 * @since 1.4
*/ */

View File

@@ -26,6 +26,7 @@ import java.awt.Rectangle;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Map;
import javax.swing.CellRendererPane; import javax.swing.CellRendererPane;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JComponent; import javax.swing.JComponent;
@@ -39,6 +40,8 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTreeUI; import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath; import javax.swing.tree.TreePath;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -94,25 +97,68 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Tree.wideSelection boolean * @uiDefault Tree.wideSelection boolean
* @uiDefault Tree.showCellFocusIndicator boolean * @uiDefault Tree.showCellFocusIndicator boolean
* *
* <!-- FlatTreeExpandedIcon -->
*
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Tree.icon.expandedColor Color
*
* <!-- FlatTreeCollapsedIcon -->
*
* @uiDefault Component.arrowType String chevron (default) or triangle
* @uiDefault Tree.icon.collapsedColor Color
*
* <!-- FlatTreeLeafIcon -->
*
* @uiDefault Tree.icon.leafColor Color
*
* <!-- FlatTreeClosedIcon -->
*
* @uiDefault Tree.icon.closedColor Color
*
* <!-- FlatTreeOpenIcon -->
*
* @uiDefault Tree.icon.openColor Color
*
* @author Karl Tauber * @author Karl Tauber
*/ */
public class FlatTreeUI public class FlatTreeUI
extends BasicTreeUI extends BasicTreeUI
implements StyleableUI
{ {
protected Color selectionBackground; @Styleable protected Color selectionBackground;
protected Color selectionForeground; @Styleable protected Color selectionForeground;
protected Color selectionInactiveBackground; @Styleable protected Color selectionInactiveBackground;
protected Color selectionInactiveForeground; @Styleable protected Color selectionInactiveForeground;
protected Color selectionBorderColor; @Styleable protected Color selectionBorderColor;
protected boolean wideSelection; @Styleable protected boolean wideSelection;
protected boolean showCellFocusIndicator; @Styleable protected boolean showCellFocusIndicator;
// for icons
// (needs to be public because icon classes are in another package)
@Styleable(dot=true) public String iconArrowType;
@Styleable(dot=true) public Color iconExpandedColor;
@Styleable(dot=true) public Color iconCollapsedColor;
@Styleable(dot=true) public Color iconLeafColor;
@Styleable(dot=true) public Color iconClosedColor;
@Styleable(dot=true) public Color iconOpenColor;
private Color defaultCellNonSelectionBackground; private Color defaultCellNonSelectionBackground;
private Color defaultSelectionBackground;
private Color defaultSelectionForeground;
private Color defaultSelectionBorderColor;
private Map<String, Object> oldStyleValues;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTreeUI(); return new FlatTreeUI();
} }
@Override
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
}
@Override @Override
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
@@ -128,6 +174,9 @@ public class FlatTreeUI
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" ); showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" ); defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
defaultSelectionBackground = selectionBackground;
defaultSelectionForeground = selectionForeground;
defaultSelectionBorderColor = selectionBorderColor;
// scale // scale
int rowHeight = FlatUIUtils.getUIInt( "Tree.rowHeight", 16 ); int rowHeight = FlatUIUtils.getUIInt( "Tree.rowHeight", 16 );
@@ -150,6 +199,10 @@ public class FlatTreeUI
selectionBorderColor = null; selectionBorderColor = null;
defaultCellNonSelectionBackground = null; defaultCellNonSelectionBackground = null;
defaultSelectionBackground = null;
defaultSelectionForeground = null;
defaultSelectionBorderColor = null;
oldStyleValues = null;
} }
@Override @Override
@@ -216,6 +269,12 @@ public class FlatTreeUI
repaintWideDropLocation( tree.getDropLocation() ); repaintWideDropLocation( tree.getDropLocation() );
} }
break; break;
case STYLE:
applyStyle( e.getNewValue() );
tree.revalidate();
tree.repaint();
break;
} }
} }
}; };
@@ -250,6 +309,28 @@ public class FlatTreeUI
return bounds; return bounds;
} }
/**
* @since 2
*/
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
}
/**
* @since 2
*/
protected Object applyStyleProperty( String key, Object value ) {
return FlatStylingSupport.applyToAnnotatedObjectOrComponent( this, tree, key, value );
}
/**
* @since 2
*/
@Override
public Map<String, Class<?>> getStyleableInfos( JComponent c ) {
return FlatStylingSupport.getAnnotatedStyleableInfos( this );
}
/** /**
* Same as super.paintRow(), but supports wide selection and uses * Same as super.paintRow(), but supports wide selection and uses
* inactive selection background/foreground if tree is not focused. * inactive selection background/foreground if tree is not focused.
@@ -289,35 +370,32 @@ public class FlatTreeUI
Component rendererComponent = currentCellRenderer.getTreeCellRendererComponent( tree, Component rendererComponent = currentCellRenderer.getTreeCellRendererComponent( tree,
path.getLastPathComponent(), isSelected, isExpanded, isLeaf, row, cellHasFocus ); path.getLastPathComponent(), isSelected, isExpanded, isLeaf, row, cellHasFocus );
// apply inactive selection background/foreground if tree is not focused // renderer background/foreground
Color oldBackgroundSelectionColor = null; Color oldBackgroundSelectionColor = null;
if( isSelected && !hasFocus && !isDropRow ) { if( isSelected && !hasFocus && !isDropRow ) {
if( rendererComponent instanceof DefaultTreeCellRenderer ) { // apply inactive selection background/foreground if tree is not focused
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent; oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionInactiveBackground );
if( renderer.getBackgroundSelectionColor() == selectionBackground ) { setRendererForeground( rendererComponent, selectionInactiveForeground );
oldBackgroundSelectionColor = renderer.getBackgroundSelectionColor();
renderer.setBackgroundSelectionColor( selectionInactiveBackground );
}
} else {
if( rendererComponent.getBackground() == selectionBackground )
rendererComponent.setBackground( selectionInactiveBackground );
}
if( rendererComponent.getForeground() == selectionForeground ) } else if( isSelected ) {
rendererComponent.setForeground( selectionInactiveForeground ); // update background/foreground if set via style
if( selectionBackground != defaultSelectionBackground )
oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionBackground );
if( selectionForeground != defaultSelectionForeground )
setRendererForeground( rendererComponent, selectionForeground );
} }
// remove focus selection border if exactly one item is selected // update focus selection border
Color oldBorderSelectionColor = null; Color oldBorderSelectionColor = null;
if( isSelected && hasFocus && if( isSelected && hasFocus &&
(!showCellFocusIndicator || tree.getMinSelectionRow() == tree.getMaxSelectionRow()) && (!showCellFocusIndicator || tree.getMinSelectionRow() == tree.getMaxSelectionRow()) )
rendererComponent instanceof DefaultTreeCellRenderer )
{ {
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent; // remove focus selection border if exactly one item is selected or if showCellFocusIndicator is false
if( renderer.getBorderSelectionColor() == selectionBorderColor ) { oldBorderSelectionColor = setRendererBorderSelectionColor( rendererComponent, null );
oldBorderSelectionColor = renderer.getBorderSelectionColor();
renderer.setBorderSelectionColor( null ); } else if( hasFocus && selectionBorderColor != defaultSelectionBorderColor ) {
} // update focus selection border if set via style
oldBorderSelectionColor = setRendererBorderSelectionColor( rendererComponent, selectionBorderColor );
} }
// paint selection background // paint selection background
@@ -365,6 +443,42 @@ public class FlatTreeUI
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor ); ((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
} }
private Color setRendererBackgroundSelectionColor( Component rendererComponent, Color color ) {
Color oldColor = null;
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
if( renderer.getBackgroundSelectionColor() == defaultSelectionBackground ) {
oldColor = renderer.getBackgroundSelectionColor();
renderer.setBackgroundSelectionColor( color );
}
} else {
if( rendererComponent.getBackground() == defaultSelectionBackground )
rendererComponent.setBackground( color );
}
return oldColor;
}
private void setRendererForeground( Component rendererComponent, Color color ) {
if( rendererComponent.getForeground() == defaultSelectionForeground )
rendererComponent.setForeground( color );
}
private Color setRendererBorderSelectionColor( Component rendererComponent, Color color ) {
Color oldColor = null;
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
if( renderer.getBorderSelectionColor() == defaultSelectionBorderColor ) {
oldColor = renderer.getBorderSelectionColor();
renderer.setBorderSelectionColor( color );
}
}
return oldColor;
}
private void paintWideSelection( Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, private void paintWideSelection( Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds,
TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf ) TreePath path, int row, boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf )
{ {

View File

@@ -863,6 +863,14 @@ debug*/
.computeIfAbsent( key, k -> newInstanceSupplier.get() ); .computeIfAbsent( key, k -> newInstanceSupplier.get() );
} }
/**
* Returns whether the component UI for the given component can be shared
* with other components. This is only possible if it does not have styles.
*/
public static boolean canUseSharedUI( JComponent c ) {
return FlatStylingSupport.getStyle( c ) == null;
}
//---- class RepaintFocusListener ----------------------------------------- //---- class RepaintFocusListener -----------------------------------------
public static class RepaintFocusListener public static class RepaintFocusListener

View File

@@ -21,6 +21,7 @@ import java.awt.Insets;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.JComponent; import javax.swing.JComponent;
import com.formdev.flatlaf.FlatClientProperties;
/** /**
* Support for MigLayout visual paddings. * Support for MigLayout visual paddings.
@@ -80,7 +81,7 @@ public class MigLayoutVisualPadding
return new Insets( focusWidth, focusWidth, focusWidth, focusWidth ); return new Insets( focusWidth, focusWidth, focusWidth, focusWidth );
} else } else
return null; return null;
}, "border" ); }, "border", FlatClientProperties.STYLE );
} }
/** /**

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2021 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
*
* https://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;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import org.junit.jupiter.api.Test;
/**
* @author Karl Tauber
*/
public class TestUIDefaultsLoader
{
@Test
void parseValue() {
assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", null ) );
assertEquals( false, UIDefaultsLoader.parseValue( "dummy", "false", null ) );
assertEquals( true, UIDefaultsLoader.parseValue( "dummy", "true", null ) );
assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "hello", null ) );
assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "\"hello\"", null ) );
assertEquals( "null", UIDefaultsLoader.parseValue( "dummy", "\"null\"", null ) );
assertEquals( 'a', UIDefaultsLoader.parseValue( "dummyChar", "a", null ) );
assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", null ) );
assertEquals( 123, UIDefaultsLoader.parseValue( "dummyWidth", "123", null ) );
assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", null ) );
assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummyWidth", "{float}1.23", null ) );
assertEquals( new Insets( 2,2,2,2 ), UIDefaultsLoader.parseValue( "dummyInsets", "2,2,2,2", null ) );
assertEquals( new Dimension( 2,2 ), UIDefaultsLoader.parseValue( "dummySize", "2,2", null ) );
assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummy", "#f00", null ) );
assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummyColor", "#f00", null ) );
}
@Test
void parseValueWithJavaType() {
assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", String.class ) );
assertEquals( false, UIDefaultsLoader.parseValue( "dummy", "false", boolean.class ) );
assertEquals( true, UIDefaultsLoader.parseValue( "dummy", "true", Boolean.class ) );
assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "hello", String.class ) );
assertEquals( "hello", UIDefaultsLoader.parseValue( "dummy", "\"hello\"", String.class ) );
assertEquals( "null", UIDefaultsLoader.parseValue( "dummy", "\"null\"", String.class ) );
assertEquals( null, UIDefaultsLoader.parseValue( "dummy", "null", String.class ) );
assertEquals( 'a', UIDefaultsLoader.parseValue( "dummy", "a", char.class ) );
assertEquals( 'a', UIDefaultsLoader.parseValue( "dummy", "a", Character.class ) );
assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", int.class ) );
assertEquals( 123, UIDefaultsLoader.parseValue( "dummy", "123", Integer.class ) );
assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", float.class ) );
assertEquals( 1.23f, UIDefaultsLoader.parseValue( "dummy", "1.23", Float.class ) );
assertEquals( new Insets( 2,2,2,2 ), UIDefaultsLoader.parseValue( "dummy", "2,2,2,2", Insets.class ) );
assertEquals( new Dimension( 2,2 ), UIDefaultsLoader.parseValue( "dummy", "2,2", Dimension.class ) );
assertEquals( new Color( 0xff0000 ), UIDefaultsLoader.parseValue( "dummy", "#f00", Color.class ) );
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,157 @@
/*
* Copyright 2021 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
*
* https://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.ui;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static com.formdev.flatlaf.FlatClientProperties.STYLE;
import java.util.function.Supplier;
import javax.swing.JEditorPane;
import javax.swing.JFormattedTextField;
import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.JTextComponent;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/**
* @author Karl Tauber
*/
public class TestFlatTextComponents
{
@BeforeAll
static void setup() {
TestUtils.setup( false );
}
@AfterAll
static void cleanup() {
TestUtils.cleanup();
}
@Test
void editorPane_updateBackground() {
textComponent_updateBackground( "EditorPane", JEditorPane::new );
}
@Test
void formattedTextField_updateBackground() {
textComponent_updateBackground( "FormattedTextField", JFormattedTextField::new );
}
@Test
void passwordField_updateBackground() {
textComponent_updateBackground( "PasswordField", JPasswordField::new );
}
@Test
void textArea_updateBackground() {
textComponent_updateBackground( "TextArea", JTextArea::new );
}
@Test
void textField_updateBackground() {
textComponent_updateBackground( "TextField", JTextField::new );
}
@Test
void textPane_updateBackground() {
textComponent_updateBackground( "TextPane", JTextPane::new );
}
@Test
void basicTextField_updateBackground() {
textComponent_updateBackground( "TextField", () -> {
JTextField c = new JTextField();
c.setUI( new BasicTextFieldUI() );
return c;
} );
}
private void textComponent_updateBackground( String prefix, Supplier<JTextComponent> createTextComponent ) {
ColorUIResource background = new ColorUIResource( 0xff0000 );
ColorUIResource inactiveBackground = new ColorUIResource( 0x00ff00 );
ColorUIResource disabledBackground = new ColorUIResource( 0x0000ff );
UIManager.put( prefix + ".background", background );
UIManager.put( prefix + ".inactiveBackground", inactiveBackground );
UIManager.put( prefix + ".disabledBackground", disabledBackground );
JTextComponent c = createTextComponent.get();
// without styling
assertEquals( background, c.getBackground() );
c.setEditable( false ); assertEquals( inactiveBackground, c.getBackground() );
c.setEnabled( false ); assertEquals( disabledBackground, c.getBackground() );
c.setEditable( true ); assertEquals( disabledBackground, c.getBackground() );
c.setEnabled( true ); assertEquals( background, c.getBackground() );
if( !c.getUI().getClass().getSimpleName().startsWith( "Flat" ) )
return;
// with styling
ColorUIResource inactiveBackground1 = new ColorUIResource( 0x00ee00 );
ColorUIResource disabledBackground1 = new ColorUIResource( 0x0000ee );
ColorUIResource inactiveBackground2 = new ColorUIResource( 0x00dd00 );
ColorUIResource disabledBackground2 = new ColorUIResource( 0x0000dd );
String style1 = "inactiveBackground: #00ee00; disabledBackground: #0000ee";
String style2 = "inactiveBackground: #00dd00; disabledBackground: #0000dd";
c.putClientProperty( STYLE, style1 );
assertEquals( background, c.getBackground() );
c.setEditable( false ); assertEquals( inactiveBackground1, c.getBackground() );
c.setEnabled( false ); assertEquals( disabledBackground1, c.getBackground() );
c.setEditable( true ); assertEquals( disabledBackground1, c.getBackground() );
c.setEnabled( true ); assertEquals( background, c.getBackground() );
c.putClientProperty( STYLE, null );
assertEquals( background, c.getBackground() );
c.setEditable( false );
c.putClientProperty( STYLE, style1 );
assertEquals( inactiveBackground1, c.getBackground() );
c.putClientProperty( STYLE, null );
assertEquals( inactiveBackground, c.getBackground() );
c.setEnabled( false );
c.putClientProperty( STYLE, style1 );
assertEquals( disabledBackground1, c.getBackground() );
// change from style1 to style2
c.putClientProperty( STYLE, style2 );
assertEquals( disabledBackground2, c.getBackground() );
c.setEnabled( true );
assertEquals( inactiveBackground2, c.getBackground() );
// remove style
c.putClientProperty( STYLE, null );
assertEquals( inactiveBackground, c.getBackground() );
}
}

View File

@@ -17,7 +17,10 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import java.awt.Font; import java.awt.Font;
import java.util.Map;
import java.util.Objects;
import javax.swing.UIManager; import javax.swing.UIManager;
import org.opentest4j.AssertionFailedError;
import com.formdev.flatlaf.FlatIntelliJLaf; import com.formdev.flatlaf.FlatIntelliJLaf;
import com.formdev.flatlaf.FlatLightLaf; import com.formdev.flatlaf.FlatLightLaf;
import com.formdev.flatlaf.FlatSystemProperties; import com.formdev.flatlaf.FlatSystemProperties;
@@ -50,4 +53,15 @@ public class TestUtils
public static void resetFont() { public static void resetFont() {
UIManager.put( "defaultFont", null ); UIManager.put( "defaultFont", null );
} }
public static void assertMapEquals( Map<?, ?> expected, Map<?, ?> actual ) {
if( !Objects.equals( expected, actual ) ) {
String expectedStr = String.valueOf( expected ).replace( ", ", ",\n" );
String actualStr = String.valueOf( actual ).replace( ", ", ",\n" );
String msg = String.format( "expected: <%s> but was: <%s>", expectedStr, actualStr );
// pass expected/actual strings to exception for nice diff in IDE
throw new AssertionFailedError( msg, expectedStr, actualStr );
}
}
} }

View File

@@ -27,7 +27,7 @@ import javax.swing.JButton;
*/ */
public class FlatButton public class FlatButton
extends JButton extends JButton
implements FlatComponentExtension implements FlatComponentExtension, FlatStyleableComponent
{ {
// NOTE: enum names must be equal to allowed strings // NOTE: enum names must be equal to allowed strings
public enum ButtonType { none, square, roundRect, tab, help, toolBarButton, borderless } public enum ButtonType { none, square, roundRect, tab, help, toolBarButton, borderless }

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JCheckBox;
/**
* Subclass of {@link JCheckBox} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatCheckBox
extends JCheckBox
implements FlatStyleableComponent
{
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JCheckBoxMenuItem;
/**
* Subclass of {@link JCheckBoxMenuItem} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatCheckBoxMenuItem
extends JCheckBoxMenuItem
implements FlatStyleableComponent
{
}

View File

@@ -27,7 +27,7 @@ import javax.swing.JComboBox;
*/ */
public class FlatComboBox<E> public class FlatComboBox<E>
extends JComboBox<E> extends JComboBox<E>
implements FlatComponentExtension implements FlatComponentExtension, FlatStyleableComponent
{ {
/** /**
* Returns the placeholder text that is only painted if the editable combo box is empty. * Returns the placeholder text that is only painted if the editable combo box is empty.

View File

@@ -26,7 +26,7 @@ import javax.swing.JEditorPane;
*/ */
public class FlatEditorPane public class FlatEditorPane
extends JEditorPane extends JEditorPane
implements FlatComponentExtension implements FlatComponentExtension, FlatStyleableComponent
{ {
/** /**
* Returns minimum width of a component. * Returns minimum width of a component.

View File

@@ -29,7 +29,7 @@ import com.formdev.flatlaf.extras.components.FlatTextField.SelectAllOnFocusPolic
*/ */
public class FlatFormattedTextField public class FlatFormattedTextField
extends JFormattedTextField extends JFormattedTextField
implements FlatComponentExtension implements FlatComponentExtension, FlatStyleableComponent
{ {
/** /**
* Returns the placeholder text that is only painted if the text field is empty. * Returns the placeholder text that is only painted if the text field is empty.

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JInternalFrame;
/**
* Subclass of {@link JInternalFrame} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatInternalFrame
extends JInternalFrame
implements FlatStyleableComponent
{
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JLabel;
/**
* Subclass of {@link JLabel} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatLabel
extends JLabel
implements FlatStyleableComponent
{
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JList;
/**
* Subclass of {@link JList} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatList<E>
extends JList<E>
implements FlatStyleableComponent
{
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JMenu;
/**
* Subclass of {@link JMenu} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatMenu
extends JMenu
implements FlatStyleableComponent
{
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JMenuBar;
/**
* Subclass of {@link JMenuBar} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatMenuBar
extends JMenuBar
implements FlatStyleableComponent
{
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JMenuItem;
/**
* Subclass of {@link JMenuItem} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatMenuItem
extends JMenuItem
implements FlatStyleableComponent
{
}

View File

@@ -29,7 +29,7 @@ import com.formdev.flatlaf.extras.components.FlatTextField.SelectAllOnFocusPolic
*/ */
public class FlatPasswordField public class FlatPasswordField
extends JPasswordField extends JPasswordField
implements FlatComponentExtension implements FlatComponentExtension, FlatStyleableComponent
{ {
/** /**
* Returns the placeholder text that is only painted if the text field is empty. * Returns the placeholder text that is only painted if the text field is empty.

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JPopupMenu;
/**
* Subclass of {@link JPopupMenu} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatPopupMenu
extends JPopupMenu
implements FlatStyleableComponent
{
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JPopupMenu;
/**
* Subclass of {@link JPopupMenu.Separator} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatPopupMenuSeparator
extends JPopupMenu.Separator
implements FlatStyleableComponent
{
}

View File

@@ -26,7 +26,7 @@ import javax.swing.JProgressBar;
*/ */
public class FlatProgressBar public class FlatProgressBar
extends JProgressBar extends JProgressBar
implements FlatComponentExtension implements FlatComponentExtension, FlatStyleableComponent
{ {
/** /**
* Returns whether the progress bar has always the larger height even if no string is painted. * Returns whether the progress bar has always the larger height even if no string is painted.

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JRadioButton;
/**
* Subclass of {@link JRadioButton} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatRadioButton
extends JRadioButton
implements FlatStyleableComponent
{
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2021 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
*
* https://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.extras.components;
import javax.swing.JRadioButtonMenuItem;
/**
* Subclass of {@link JRadioButtonMenuItem} that provides easy access to FlatLaf specific client properties.
*
* @author Karl Tauber
* @since 2
*/
public class FlatRadioButtonMenuItem
extends JRadioButtonMenuItem
implements FlatStyleableComponent
{
}

View File

@@ -26,7 +26,7 @@ import javax.swing.JScrollBar;
*/ */
public class FlatScrollBar public class FlatScrollBar
extends JScrollBar extends JScrollBar
implements FlatComponentExtension implements FlatComponentExtension, FlatStyleableComponent
{ {
/** /**
* Returns whether the decrease/increase arrow buttons of a scrollbar are shown. * Returns whether the decrease/increase arrow buttons of a scrollbar are shown.

Some files were not shown because too many files have changed in this diff Show More