Styling: basic support for "classes" (similar to CSS classes) using client property FlatLaf.styleClass

This commit is contained in:
Karl Tauber
2021-09-25 14:34:21 +02:00
parent cce91ea16d
commit b6be0462a5
39 changed files with 951 additions and 118 deletions

View File

@@ -145,6 +145,38 @@ public interface FlatClientProperties
*/
String STYLE = "FlatLaf.style";
/**
* Specifies the style class(es) of a component as String
* or as {@link java.util.List}<String>.
* <p>
* The style rules must be defined in UI defaults either as strings (in CSS syntax)
* or as {@link java.util.Map}&lt;String, Object&gt; (with binary values).
* The key must be in syntax: {@code [style]type.styleClass}, where the type is optional.
* E.g. in FlatLaf properties file:
* <pre>{@code
* [style]Button.primary = borderColor: #08f; background: #08f; foreground: #fff
* [style].secondary = borderColor: #0f8; background: #0f8
* }</pre>
* or in Java code:
* <pre>{@code
* UIManager.put( "[style]Button.primary", "borderColor: #08f; background: #08f; foreground: #fff" );
* UIManager.put( "[style].secondary", "borderColor: #0f8; background: #0f8" );
* }</pre>
* The rule "Button.primary" can be applied to buttons only.
* The rule ".secondary" can be applied to any component.
* <p>
* To have similar behaviour as in CSS, first the rule without type is applied,
* then the rule with type.
* E.g. setting style class to "foo" on a {@code JButton} uses rules
* from UI default keys "[style].foo" and "[style]Button.foo".
* <p>
* <strong>Components</strong> {@link javax.swing.JComponent}<br>
* <strong>Value type</strong> {@link java.lang.String}, {@code String[]} or {@link java.util.List}&lt;String&gt;<br>
*
* @since 2
*/
String STYLE_CLASS = "FlatLaf.styleClass";
/**
* Specifies minimum width of a component.
* <p>

View File

@@ -152,6 +152,7 @@ public class FlatButtonUI
: new FlatButtonUI( false );
}
/** @since 2 */
protected FlatButtonUI( boolean shared ) {
this.shared = shared;
}
@@ -160,7 +161,7 @@ public class FlatButtonUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( (AbstractButton) c, FlatStylingSupport.getStyle( c ) );
installStyle( (AbstractButton) c );
}
@Override
@@ -254,19 +255,29 @@ public class FlatButtonUI
break;
case STYLE:
Object style = e.getNewValue();
if( style != null && shared ) {
case STYLE_CLASS:
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
b.updateUI();
} else
applyStyle( b, style );
installStyle( b );
b.revalidate();
b.repaint();
break;
}
}
/** @since 2 */
protected void installStyle( AbstractButton b ) {
applyStyle( b, FlatStylingSupport.getResolvedStyle( b, getStyleType() ) );
}
/** @since 2 */
String getStyleType() {
return "Button";
}
/** @since 2 */
protected void applyStyle( AbstractButton b, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,

View File

@@ -72,7 +72,7 @@ public class FlatCheckBoxMenuItemUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( menuItem ) );
installStyle();
}
@Override
@@ -98,7 +98,12 @@ public class FlatCheckBoxMenuItemUI
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) );
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "CheckBoxMenuItem" ) );
}
/** @since 2 */

View File

@@ -57,4 +57,10 @@ public class FlatCheckBoxUI
public String getPropertyPrefix() {
return "CheckBox.";
}
/** @since 2 */
@Override
String getStyleType() {
return "CheckBox";
}
}

View File

@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.FlatClientProperties.*;
import static com.formdev.flatlaf.util.UIScale.scale;
import static com.formdev.flatlaf.util.UIScale.unscale;
import java.awt.Color;
@@ -69,7 +70,6 @@ import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.text.JTextComponent;
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;
@@ -155,7 +155,7 @@ public class FlatComboBoxUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( comboBox ) );
installStyle();
}
@Override
@@ -341,16 +341,28 @@ public class FlatComboBoxUI
} else if( editor != null && source == comboBox && propertyName == "componentOrientation" ) {
ComponentOrientation o = (ComponentOrientation) e.getNewValue();
editor.applyComponentOrientation( o );
} else if( editor != null && FlatClientProperties.PLACEHOLDER_TEXT.equals( propertyName ) )
editor.repaint();
else if( FlatClientProperties.COMPONENT_ROUND_RECT.equals( propertyName ) )
comboBox.repaint();
else if( FlatClientProperties.MINIMUM_WIDTH.equals( propertyName ) )
comboBox.revalidate();
else if( FlatClientProperties.STYLE.equals( propertyName ) ) {
applyStyle( e.getNewValue() );
comboBox.revalidate();
comboBox.repaint();
} else {
switch( propertyName ) {
case PLACEHOLDER_TEXT:
if( editor != null )
editor.repaint();
break;
case COMPONENT_ROUND_RECT:
comboBox.repaint();
break;
case MINIMUM_WIDTH:
comboBox.revalidate();
break;
case STYLE:
case STYLE_CLASS:
installStyle();
comboBox.revalidate();
comboBox.repaint();
break;
}
}
};
}
@@ -419,7 +431,7 @@ public class FlatComboBoxUI
unscale( Math.max( scale( padding.right ) - insets.right, 0 ) )
);
}
textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, pad );
textField.putClientProperty( TEXT_FIELD_PADDING, pad );
}
private void updateEditorColors() {
@@ -438,6 +450,11 @@ public class FlatComboBoxUI
return new FlatComboBoxButton();
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( comboBox, "ComboBox" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
Insets oldPadding = padding;

View File

@@ -25,7 +25,6 @@ import java.awt.Insets;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.function.Consumer;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.UIManager;
@@ -91,7 +90,7 @@ public class FlatEditorPaneUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -155,23 +154,29 @@ public class FlatEditorPaneUI
updateBackground();
super.propertyChange( e );
propertyChange( getComponent(), e, this::applyStyle );
propertyChange( getComponent(), e, this::installStyle );
}
static void propertyChange( JTextComponent c, PropertyChangeEvent e, Consumer<Object> applyStyle ) {
static void propertyChange( JTextComponent c, PropertyChangeEvent e, Runnable installStyle ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.MINIMUM_WIDTH:
c.revalidate();
break;
case FlatClientProperties.STYLE:
applyStyle.accept( e.getNewValue() );
case FlatClientProperties.STYLE_CLASS:
installStyle.run();
c.revalidate();
c.repaint();
break;
}
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "EditorPane" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldDisabledBackground = disabledBackground;

View File

@@ -60,4 +60,10 @@ public class FlatFormattedTextFieldUI
protected String getPropertyPrefix() {
return "FormattedTextField";
}
/** @since 2 */
@Override
String getStyleType() {
return "FormattedTextField";
}
}

View File

@@ -116,7 +116,7 @@ public class FlatInternalFrameUI
windowResizer = createWindowResizer();
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -148,10 +148,15 @@ public class FlatInternalFrameUI
@Override
protected PropertyChangeListener createPropertyChangeListener() {
return FlatStylingSupport.createPropertyChangeListener( frame, this::applyStyle,
return FlatStylingSupport.createPropertyChangeListener( frame, this::installStyle,
super.createPropertyChangeListener() );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( frame, "InternalFrame" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -81,7 +81,7 @@ public class FlatLabelUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( (JLabel) c, FlatStylingSupport.getStyle( c ) );
installStyle( (JLabel) c );
}
@Override
@@ -117,21 +117,25 @@ public class FlatLabelUI
if( name == "text" || name == "font" || name == "foreground" ) {
JLabel label = (JLabel) e.getSource();
updateHTMLRenderer( label, label.getText(), true );
} else if( name.equals( FlatClientProperties.STYLE ) ) {
} else if( name.equals( FlatClientProperties.STYLE ) || name.equals( FlatClientProperties.STYLE_CLASS ) ) {
JLabel label = (JLabel) e.getSource();
Object style = e.getNewValue();
if( style != null && shared ) {
if( shared && FlatStylingSupport.hasStyleProperty( label ) ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
label.updateUI();
} else
applyStyle( label, style );
installStyle( label );
label.revalidate();
label.repaint();
} else
super.propertyChange( e );
}
/** @since 2 */
protected void installStyle( JLabel c ) {
applyStyle( c, FlatStylingSupport.getResolvedStyle( c, "Label" ) );
}
/** @since 2 */
protected void applyStyle( JLabel c, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,

View File

@@ -91,7 +91,7 @@ public class FlatListUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -151,7 +151,8 @@ public class FlatListUI
break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
case FlatClientProperties.STYLE_CLASS:
installStyle();
list.revalidate();
list.repaint();
break;
@@ -159,6 +160,11 @@ public class FlatListUI
};
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( list, "List" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
Color oldSelectionBackground = selectionBackground;

View File

@@ -39,7 +39,6 @@ import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicMenuBarUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
@@ -91,7 +90,7 @@ public class FlatMenuBarUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -113,16 +112,15 @@ public class FlatMenuBarUI
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
menuBar, this::applyStyle, null );
menuBar.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( menuBar, this::installStyle, null );
menuBar.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
menuBar.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
menuBar.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
@@ -138,6 +136,11 @@ public class FlatMenuBarUI
map.put( "takeFocus", new TakeFocus() );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( menuBar, "MenuBar" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -73,7 +73,7 @@ public class FlatMenuItemUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( menuItem ) );
installStyle();
}
@Override
@@ -99,7 +99,12 @@ public class FlatMenuItemUI
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) );
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "MenuItem" ) );
}
/** @since 2 */

View File

@@ -92,7 +92,7 @@ public class FlatMenuUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( menuItem ) );
installStyle();
}
@Override
@@ -145,7 +145,12 @@ public class FlatMenuUI
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) );
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "Menu" ) );
}
/** @since 2 */

View File

@@ -162,6 +162,12 @@ public class FlatPasswordFieldUI
}
}
/** @since 2 */
@Override
String getStyleType() {
return "PasswordField";
}
/** @since 2 */
@Override
protected Object applyStyleProperty( String key, Object value ) {

View File

@@ -53,4 +53,10 @@ public class FlatPopupMenuSeparatorUI
protected String getPropertyPrefix() {
return "PopupMenuSeparator";
}
/** @since 2 */
@Override
String getStyleType() {
return "PopupMenuSeparator";
}
}

View File

@@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JComponent;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicPopupMenuUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
/**
@@ -53,7 +52,7 @@ public class FlatPopupMenuUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -68,18 +67,23 @@ public class FlatPopupMenuUI
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( popupMenu, this::applyStyle, null );
popupMenu.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( popupMenu, this::installStyle, null );
popupMenu.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
popupMenu.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
popupMenu.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( popupMenu, "PopupMenu" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -78,7 +78,7 @@ public class FlatProgressBarUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( progressBar ) );
installStyle();
}
@Override
@@ -112,7 +112,8 @@ public class FlatProgressBarUI
break;
case STYLE:
applyStyle( e.getNewValue() );
case STYLE_CLASS:
installStyle();
progressBar.revalidate();
progressBar.repaint();
break;
@@ -129,6 +130,11 @@ public class FlatProgressBarUI
propertyChangeListener = null;
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( progressBar, "ProgressBar" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -72,7 +72,7 @@ public class FlatRadioButtonMenuItemUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( menuItem ) );
installStyle();
}
@Override
@@ -98,7 +98,12 @@ public class FlatRadioButtonMenuItemUI
@Override
protected PropertyChangeListener createPropertyChangeListener( JComponent c ) {
return FlatStylingSupport.createPropertyChangeListener( c, this::applyStyle, super.createPropertyChangeListener( c ) );
return FlatStylingSupport.createPropertyChangeListener( c, this::installStyle, super.createPropertyChangeListener( c ) );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( menuItem, "RadioButtonMenuItem" ) );
}
/** @since 2 */

View File

@@ -90,7 +90,7 @@ public class FlatRadioButtonUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( (AbstractButton) c, FlatStylingSupport.getStyle( c ) );
installStyle( (AbstractButton) c );
}
@Override
@@ -134,19 +134,29 @@ public class FlatRadioButtonUI
protected void propertyChange( AbstractButton b, PropertyChangeEvent e ) {
switch( e.getPropertyName() ) {
case FlatClientProperties.STYLE:
Object style = e.getNewValue();
if( style != null && shared ) {
case FlatClientProperties.STYLE_CLASS:
if( shared && FlatStylingSupport.hasStyleProperty( b ) ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
b.updateUI();
} else
applyStyle( b, style );
installStyle( b );
b.revalidate();
b.repaint();
break;
}
}
/** @since 2 */
protected void installStyle( AbstractButton b ) {
applyStyle( b, FlatStylingSupport.getResolvedStyle( b, getStyleType() ) );
}
/** @since 2 */
String getStyleType() {
return "RadioButton";
}
/** @since 2 */
protected void applyStyle( AbstractButton b, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,

View File

@@ -115,7 +115,7 @@ public class FlatScrollBarUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -199,7 +199,8 @@ public class FlatScrollBarUI
break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
case FlatClientProperties.STYLE_CLASS:
installStyle();
scrollbar.revalidate();
scrollbar.repaint();
break;
@@ -220,6 +221,11 @@ public class FlatScrollBarUI
};
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( scrollbar, "ScrollBar" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -87,7 +87,7 @@ public class FlatScrollPaneUI
int focusWidth = UIManager.getInt( "Component.focusWidth" );
LookAndFeel.installProperty( c, "opaque", focusWidth == 0 );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
MigLayoutVisualPadding.install( scrollpane );
}
@@ -287,7 +287,8 @@ public class FlatScrollPaneUI
break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
case FlatClientProperties.STYLE_CLASS:
installStyle();
scrollpane.revalidate();
scrollpane.repaint();
break;
@@ -301,6 +302,11 @@ public class FlatScrollPaneUI
return handler;
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( scrollpane, "ScrollPane" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -28,7 +28,6 @@ import javax.swing.JSeparator;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
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;
@@ -80,7 +79,7 @@ public class FlatSeparatorUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( (JSeparator) c, FlatStylingSupport.getStyle( c ) );
installStyle( (JSeparator) c );
}
@Override
@@ -110,29 +109,39 @@ public class FlatSeparatorUI
super.installListeners( s );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
s, style -> applyStyle( s, this, style ), null );
s.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
s, () -> stylePropertyChange( s ), null );
s.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners( JSeparator s ) {
super.uninstallListeners( s );
s.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
s.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
private static void applyStyle( JSeparator s, FlatSeparatorUI ui, Object style ) {
if( style != null && ui.shared ) {
private void stylePropertyChange( JSeparator s ) {
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
s.updateUI();
} else
ui.applyStyle( s, style );
installStyle( s );
s.revalidate();
s.repaint();
}
/** @since 2 */
protected void installStyle( JSeparator s ) {
applyStyle( s, FlatStylingSupport.getResolvedStyle( s, getStyleType() ) );
}
/** @since 2 */
String getStyleType() {
return "Separator";
}
/** @since 2 */
protected void applyStyle( JSeparator s, Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style,

View File

@@ -121,7 +121,7 @@ public class FlatSliderUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( slider ) );
installStyle();
}
@Override
@@ -188,10 +188,15 @@ public class FlatSliderUI
@Override
protected PropertyChangeListener createPropertyChangeListener( JSlider slider ) {
return FlatStylingSupport.createPropertyChangeListener( slider, this::applyStyle,
return FlatStylingSupport.createPropertyChangeListener( slider, this::installStyle,
super.createPropertyChangeListener( slider ) );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( slider, "Slider" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -114,7 +114,7 @@ public class FlatSpinnerUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( spinner ) );
installStyle();
}
@Override
@@ -190,6 +190,11 @@ public class FlatSpinnerUI
return handler;
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( spinner, "Spinner" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
@@ -530,7 +535,8 @@ public class FlatSpinnerUI
break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
case FlatClientProperties.STYLE_CLASS:
installStyle();
spinner.revalidate();
spinner.repaint();
break;

View File

@@ -34,7 +34,6 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
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;
@@ -90,7 +89,7 @@ public class FlatSplitPaneUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( splitPane ) );
installStyle();
}
@Override
@@ -121,15 +120,15 @@ public class FlatSplitPaneUI
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::applyStyle, null );
splitPane.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( splitPane, this::installStyle, null );
splitPane.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
splitPane.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
splitPane.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
@@ -138,6 +137,11 @@ public class FlatSplitPaneUI
return new FlatSplitPaneDivider( this );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( splitPane, "SplitPane" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -26,10 +26,10 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
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;
@@ -73,6 +73,150 @@ public class FlatStylingSupport
Map<String, Class<?>> getStyleableInfos();
}
/**
* Returns the style specified in client property {@link FlatClientProperties#STYLE}.
*/
public static Object getStyle( JComponent c ) {
return c.getClientProperty( FlatClientProperties.STYLE );
}
/**
* Returns the style class(es) specified in client property {@link FlatClientProperties#STYLE_CLASS}.
*/
public static Object getStyleClass( JComponent c ) {
return c.getClientProperty( FlatClientProperties.STYLE_CLASS );
}
static boolean hasStyleProperty( JComponent c ) {
return getStyle( c ) != null || getStyleClass( c ) != null;
}
public static Object getResolvedStyle( JComponent c, String type ) {
Object style = getStyle( c );
Object styleClass = getStyleClass( c );
Object styleForClasses = getStyleForClasses( styleClass, type );
return joinStyles( styleForClasses, style );
}
/**
* Returns the styles for the given style class(es) and the given type.
* <p>
* The style rules must be defined in UI defaults either as strings (in CSS syntax)
* or as {@link java.util.Map}&lt;String, Object&gt; (with binary values).
* The key must be in syntax: {@code [style]type.styleClass}, where the type is optional.
* E.g. in FlatLaf properties file:
* <pre>{@code
* [style]Button.primary = borderColor: #08f; background: #08f; foreground: #fff
* [style].secondary = borderColor: #0f8; background: #0f8
* }</pre>
* or in Java code:
* <pre>{@code
* UIManager.put( "[style]Button.primary", "borderColor: #08f; background: #08f; foreground: #fff" );
* UIManager.put( "[style].secondary", "borderColor: #0f8; background: #0f8" );
* }</pre>
* The rule "Button.primary" can be applied to buttons only.
* The rule ".secondary" can be applied to any component.
* <p>
* To have similar behaviour as in CSS, this method first gets the rule without type,
* then the rule with type and concatenates both rules.
* E.g. invoking this method with parameters styleClass="foo" and type="Button" does following:
* <pre>{@code
* return joinStyles(
* UIManager.get( "[style].foo" ),
* UIManager.get( "[style]Button.foo" ) );
* }</pre>
*
* @param styleClass the style class(es) either as string (single class)
* or as {@code String[]} or {@link java.util.List}&lt;String&gt; (multiple classes)
* @param type the type of the component
* @return the styles
*/
public static Object getStyleForClasses( Object styleClass, String type ) {
if( styleClass == null )
return null;
if( styleClass instanceof String )
return getStyleForClass( (String) styleClass, type );
else if( styleClass instanceof String[] ) {
Object style = null;
for( String cls : (String[]) styleClass )
style = joinStyles( style, getStyleForClass( cls, type ) );
return style;
} else if( styleClass instanceof List<?> ) {
Object style = null;
for( Object cls : (List<?>) styleClass )
style = joinStyles( style, getStyleForClass( (String) cls, type ) );
return style;
} else
return null;
}
private static Object getStyleForClass( String styleClass, String type ) {
return joinStyles(
UIManager.get( "[style]." + styleClass ),
UIManager.get( "[style]" + type + '.' + styleClass ) );
}
/**
* Joins two styles. They can be either strings (in CSS syntax)
* or {@link java.util.Map}&lt;String, Object&gt; (with binary values).
* <p>
* If both styles are strings, then a joined string is returned.
* If both styles are maps, then a joined map is returned.
* If one style is a map and the other style a string, then the string
* is parsed (using {@link #parse(String)}) to a map and a joined map is returned.
*
* @param style1 first style as string or map, or {@code null}
* @param style2 second style as string or map, or {@code null}
* @return new joined style
*/
@SuppressWarnings( "unchecked" )
public static Object joinStyles( Object style1, Object style2 ) {
if( style1 == null )
return style2;
if( style2 == null )
return style1;
// join two strings
if( style1 instanceof String && style2 instanceof String )
return style1 + "; " + style2;
// convert first style to map
Map<String, Object> map1 = (style1 instanceof String)
? parse( (String) style1 )
: (Map<String, Object>) style1;
if( map1 == null )
return style2;
// convert second style to map
Map<String, Object> map2 = (style2 instanceof String)
? parse( (String) style2 )
: (Map<String, Object>) style2;
if( map2 == null )
return style1;
// join two maps
Map<String, Object> map = new HashMap<>( map1 );
map.putAll( map2 );
return map;
}
/**
* Concatenates two styles in CSS syntax.
*
* @param style1 first style, or {@code null}
* @param style2 second style, or {@code null}
* @return concatenation of the two styles separated by a semicolon
*/
public static String concatStyles( String style1, String style2 ) {
if( style1 == null )
return style2;
if( style2 == null )
return style1;
return style1 + "; " + style2;
}
/**
* Parses styles in CSS syntax ("key1: value1; key2: value2; ..."),
* converts the value strings into binary and invokes the given function
@@ -408,21 +552,20 @@ public class FlatStylingSupport
}
}
public static Object getStyle( JComponent c ) {
return c.getClientProperty( FlatClientProperties.STYLE );
}
static PropertyChangeListener createPropertyChangeListener( JComponent c,
Consumer<Object> applyStyle, PropertyChangeListener superListener )
Runnable installStyle, PropertyChangeListener superListener )
{
return e -> {
if( superListener != null )
superListener.propertyChange( e );
if( FlatClientProperties.STYLE.equals( e.getPropertyName() ) ) {
applyStyle.accept( e.getNewValue() );
c.revalidate();
c.repaint();
switch( e.getPropertyName() ) {
case FlatClientProperties.STYLE:
case FlatClientProperties.STYLE_CLASS:
installStyle.run();
c.revalidate();
c.repaint();
break;
}
};
}

View File

@@ -269,7 +269,7 @@ public class FlatTabbedPaneUI
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -572,6 +572,11 @@ public class FlatTabbedPaneUI
return new FlatScrollableTabButton( direction );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( tabPane, "TabbedPane" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
@@ -2439,7 +2444,8 @@ public class FlatTabbedPaneUI
break;
case STYLE:
applyStyle( e.getNewValue() );
case STYLE_CLASS:
installStyle();
tabPane.revalidate();
tabPane.repaint();
break;

View File

@@ -41,7 +41,6 @@ import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.TableCellRenderer;
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;
@@ -104,7 +103,7 @@ public class FlatTableHeaderUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -129,18 +128,23 @@ public class FlatTableHeaderUI
protected void installListeners() {
super.installListeners();
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( header, this::applyStyle, null );
header.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener( header, this::installStyle, null );
header.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
header.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
header.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( header, "TableHeader" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -126,7 +126,7 @@ public class FlatTableUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -197,7 +197,8 @@ public class FlatTableUI
break;
case FlatClientProperties.STYLE:
applyStyle( e.getNewValue() );
case FlatClientProperties.STYLE_CLASS:
installStyle();
table.revalidate();
table.repaint();
break;
@@ -235,6 +236,11 @@ public class FlatTableUI
};
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( table, "Table" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
Color oldSelectionBackground = selectionBackground;

View File

@@ -86,7 +86,7 @@ public class FlatTextAreaUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -143,7 +143,12 @@ public class FlatTextAreaUI
updateBackground();
super.propertyChange( e );
FlatEditorPaneUI.propertyChange( getComponent(), e, this::applyStyle );
FlatEditorPaneUI.propertyChange( getComponent(), e, this::installStyle );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "TextArea" ) );
}
/** @since 2 */

View File

@@ -114,7 +114,7 @@ public class FlatTextFieldUI
leadingIcon = clientProperty( c, TEXT_FIELD_LEADING_ICON, null, Icon.class );
trailingIcon = clientProperty( c, TEXT_FIELD_TRAILING_ICON, null, Icon.class );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -209,7 +209,8 @@ public class FlatTextFieldUI
break;
case STYLE:
applyStyle( e.getNewValue() );
case STYLE_CLASS:
installStyle();
c.revalidate();
c.repaint();
break;
@@ -226,6 +227,16 @@ public class FlatTextFieldUI
}
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), getStyleType() ) );
}
/** @since 2 */
String getStyleType() {
return "TextField";
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldDisabledBackground = disabledBackground;

View File

@@ -87,7 +87,7 @@ public class FlatTextPaneUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -151,7 +151,12 @@ public class FlatTextPaneUI
updateBackground();
super.propertyChange( e );
FlatEditorPaneUI.propertyChange( getComponent(), e, this::applyStyle );
FlatEditorPaneUI.propertyChange( getComponent(), e, this::installStyle );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( getComponent(), "TextPane" ) );
}
/** @since 2 */

View File

@@ -96,6 +96,11 @@ public class FlatToggleButtonUI
super( shared );
}
@Override
String getStyleType() {
return "ToggleButton";
}
@Override
protected String getPropertyPrefix() {
return "ToggleButton.";

View File

@@ -31,7 +31,6 @@ import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
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;
@@ -74,7 +73,7 @@ public class FlatToolBarSeparatorUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle( (JSeparator) c );
}
@Override
@@ -106,29 +105,34 @@ public class FlatToolBarSeparatorUI
super.installListeners( s );
propertyChangeListener = FlatStylingSupport.createPropertyChangeListener(
s, style -> applyStyle( s, this, style ), null );
s.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
s, () -> stylePropertyChange( s ), null );
s.addPropertyChangeListener( propertyChangeListener );
}
@Override
protected void uninstallListeners( JSeparator s ) {
super.uninstallListeners( s );
s.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
s.removePropertyChangeListener( propertyChangeListener );
propertyChangeListener = null;
}
private static void applyStyle( JSeparator s, FlatToolBarSeparatorUI ui, Object style ) {
if( style != null && ui.shared ) {
private void stylePropertyChange( JSeparator s ) {
if( shared && FlatStylingSupport.hasStyleProperty( s ) ) {
// unshare component UI if necessary
// updateUI() invokes applyStyle() from installUI()
s.updateUI();
} else
ui.applyStyle( style );
installStyle( s );
s.revalidate();
s.repaint();
}
/** @since 2 */
protected void installStyle( JSeparator s ) {
applyStyle( FlatStylingSupport.getResolvedStyle( s, "ToolBarSeparator" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -83,7 +83,7 @@ public class FlatToolBarUI
if( !focusableButtons )
setButtonsFocusable( false );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -133,7 +133,12 @@ public class FlatToolBarUI
@Override
protected PropertyChangeListener createPropertyListener() {
return FlatStylingSupport.createPropertyChangeListener( toolBar, this::applyStyle, super.createPropertyListener() );
return FlatStylingSupport.createPropertyChangeListener( toolBar, this::installStyle, super.createPropertyListener() );
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( toolBar, "ToolBar" ) );
}
/** @since 2 */

View File

@@ -156,7 +156,7 @@ public class FlatTreeUI
public void installUI( JComponent c ) {
super.installUI( c );
applyStyle( FlatStylingSupport.getStyle( c ) );
installStyle();
}
@Override
@@ -271,7 +271,8 @@ public class FlatTreeUI
break;
case STYLE:
applyStyle( e.getNewValue() );
case STYLE_CLASS:
installStyle();
tree.revalidate();
tree.repaint();
break;
@@ -309,6 +310,11 @@ public class FlatTreeUI
return bounds;
}
/** @since 2 */
protected void installStyle() {
applyStyle( FlatStylingSupport.getResolvedStyle( tree, "Tree" ) );
}
/** @since 2 */
protected void applyStyle( Object style ) {
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );

View File

@@ -370,14 +370,16 @@ public class FlatUIUtils
* <li>an (optional) component border
* <li>the (optional) component background
* </ul>
* <p>
*
* Each part is painted only if the corresponding part color is not {@code null}.
* The parts are painted in this order:
* <p>
* <ol>
* <li>background
* <li>focus border
* <li>border
* </ol>
* <p>
*
* <strong>Background</strong>:
* The bounds of the filled round rectangle are
@@ -939,7 +941,7 @@ debug*/
* with other components. This is only possible if it does not have styles.
*/
public static boolean canUseSharedUI( JComponent c ) {
return FlatStylingSupport.getStyle( c ) == null;
return !FlatStylingSupport.hasStyleProperty( c );
}
//---- class RepaintFocusListener -----------------------------------------

View File

@@ -81,7 +81,7 @@ public class MigLayoutVisualPadding
return new Insets( focusWidth, focusWidth, focusWidth, focusWidth );
} else
return null;
}, "border", FlatClientProperties.STYLE );
}, "border", FlatClientProperties.STYLE, FlatClientProperties.STYLE_CLASS );
}
/**
@@ -100,7 +100,7 @@ public class MigLayoutVisualPadding
c.addPropertyChangeListener( (FlatMigListener) e -> {
String propertyName = e.getPropertyName();
for( String name : propertyNames ) {
if( name == propertyName ) {
if( name.equals( propertyName ) ) {
setVisualPadding( c, getPaddingFunction.apply( c ) );
break;
}