TextComponents:

- use focusedBackground only if editable (and enabled)
- prefer explicit set background color over focusedBackground
- added FlatTextFieldUI.getBackground() used by all text components
- support EditorPane.focusedBackground
- support TextPane.focusedBackground

(issue #335)
This commit is contained in:
Karl Tauber
2021-06-12 20:46:59 +02:00
parent b99fb8b11f
commit a51294d570
9 changed files with 146 additions and 50 deletions

View File

@@ -17,15 +17,16 @@
package com.formdev.flatlaf.ui; package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.util.UIScale.scale; import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
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.UIResource;
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;
@@ -53,6 +54,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* *
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault EditorPane.focusedBackground Color optional
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -61,8 +63,10 @@ public class FlatEditorPaneUI
{ {
protected int minimumWidth; protected int minimumWidth;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color focusedBackground;
private Object oldHonorDisplayProperties; private Object oldHonorDisplayProperties;
private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatEditorPaneUI(); return new FlatEditorPaneUI();
@@ -72,8 +76,10 @@ public class FlatEditorPaneUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
// use component font and foreground for HTML text // use component font and foreground for HTML text
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES ); oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
@@ -84,9 +90,28 @@ public class FlatEditorPaneUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
focusedBackground = null;
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties ); getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
} }
@Override
protected void installListeners() {
super.installListeners();
// necessary to update focus background
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
getComponent().addFocusListener( focusListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
getComponent().removeFocusListener( focusListener );
focusListener = null;
}
@Override @Override
protected void propertyChange( PropertyChangeEvent e ) { protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e ); super.propertyChange( e );
@@ -128,14 +153,11 @@ public class FlatEditorPaneUI
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
}
// for compatibility with IntelliJ themes static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) { g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) );
FlatUIUtils.paintParentBackground( g, c ); g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
return;
}
super.paintBackground( g );
} }
} }

View File

@@ -44,6 +44,7 @@ import javax.swing.plaf.ComponentUI;
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault FormattedTextField.placeholderForeground Color * @uiDefault FormattedTextField.placeholderForeground Color
* @uiDefault FormattedTextField.focusedBackground Color optional
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
* @uiDefault TextComponent.selectAllOnMouseClick boolean * @uiDefault TextComponent.selectAllOnMouseClick boolean
* *

View File

@@ -50,7 +50,6 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* @uiDefault PasswordField.disabledBackground Color used if not enabled * @uiDefault PasswordField.disabledBackground Color used if not enabled
* @uiDefault PasswordField.inactiveBackground Color used if not editable * @uiDefault PasswordField.inactiveBackground Color used if not editable
* @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground) * @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault PasswordField.focusedBackground Color optional
* @uiDefault PasswordField.border Border * @uiDefault PasswordField.border Border
* @uiDefault PasswordField.margin Insets * @uiDefault PasswordField.margin Insets
* @uiDefault PasswordField.echoChar character * @uiDefault PasswordField.echoChar character
@@ -61,6 +60,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault PasswordField.placeholderForeground Color * @uiDefault PasswordField.placeholderForeground Color
* @uiDefault PasswordField.focusedBackground Color optional
* @uiDefault PasswordField.showCapsLock boolean * @uiDefault PasswordField.showCapsLock boolean
* @uiDefault PasswordField.capsLockIcon Icon * @uiDefault PasswordField.capsLockIcon Icon
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
@@ -117,7 +117,10 @@ public class FlatPasswordFieldUI
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() ); // necessary to update focus border and background
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null );
// update caps lock indicator
capsLockListener = new KeyAdapter() { capsLockListener = new KeyAdapter() {
@Override @Override
public void keyPressed( KeyEvent e ) { public void keyPressed( KeyEvent e ) {

View File

@@ -20,6 +20,7 @@ import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JTextArea; import javax.swing.JTextArea;
@@ -42,7 +43,6 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* @uiDefault TextArea.selectionBackground Color * @uiDefault TextArea.selectionBackground Color
* @uiDefault TextArea.selectionForeground Color * @uiDefault TextArea.selectionForeground Color
* @uiDefault TextArea.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground) * @uiDefault TextArea.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault TextArea.focusedBackground Color optional
* @uiDefault TextArea.border Border * @uiDefault TextArea.border Border
* @uiDefault TextArea.margin Insets * @uiDefault TextArea.margin Insets
* @uiDefault TextArea.caretBlinkRate int default is 500 milliseconds * @uiDefault TextArea.caretBlinkRate int default is 500 milliseconds
@@ -53,6 +53,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault TextArea.disabledBackground Color used if not enabled * @uiDefault TextArea.disabledBackground Color used if not enabled
* @uiDefault TextArea.inactiveBackground Color used if not editable * @uiDefault TextArea.inactiveBackground Color used if not editable
* @uiDefault TextArea.focusedBackground Color optional
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -66,6 +67,8 @@ public class FlatTextAreaUI
protected Color inactiveBackground; protected Color inactiveBackground;
protected Color focusedBackground; protected Color focusedBackground;
private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTextAreaUI(); return new FlatTextAreaUI();
} }
@@ -99,6 +102,23 @@ public class FlatTextAreaUI
focusedBackground = null; focusedBackground = null;
} }
@Override
protected void installListeners() {
super.installListeners();
// necessary to update focus background
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
getComponent().addFocusListener( focusListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
getComponent().removeFocusListener( focusListener );
focusListener = null;
}
@Override @Override
protected void propertyChange( PropertyChangeEvent e ) { protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e ); super.propertyChange( e );
@@ -160,20 +180,6 @@ public class FlatTextAreaUI
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
// for compatibility with IntelliJ themes
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
FlatUIUtils.paintParentBackground( g, c );
return;
}
if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) ) {
g.setColor( focusedBackground );
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
return;
}
super.paintBackground( g );
} }
} }

View File

@@ -55,7 +55,6 @@ import com.formdev.flatlaf.util.JavaCompatibility;
* @uiDefault TextField.disabledBackground Color used if not enabled * @uiDefault TextField.disabledBackground Color used if not enabled
* @uiDefault TextField.inactiveBackground Color used if not editable * @uiDefault TextField.inactiveBackground Color used if not editable
* @uiDefault TextField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground) * @uiDefault TextField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground)
* @uiDefault TextField.focusedBackground Color optional
* @uiDefault TextField.border Border * @uiDefault TextField.border Border
* @uiDefault TextField.margin Insets * @uiDefault TextField.margin Insets
* @uiDefault TextField.caretBlinkRate int default is 500 milliseconds * @uiDefault TextField.caretBlinkRate int default is 500 milliseconds
@@ -65,6 +64,7 @@ import com.formdev.flatlaf.util.JavaCompatibility;
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault TextField.placeholderForeground Color * @uiDefault TextField.placeholderForeground Color
* @uiDefault TextField.focusedBackground Color optional
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
* @uiDefault TextComponent.selectAllOnMouseClick boolean * @uiDefault TextComponent.selectAllOnMouseClick boolean
* *
@@ -113,7 +113,8 @@ public class FlatTextFieldUI
protected void installListeners() { protected void installListeners() {
super.installListeners(); super.installListeners();
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() ); // necessary to update focus border and background
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null );
getComponent().addFocusListener( focusListener ); getComponent().addFocusListener( focusListener );
} }
@@ -184,18 +185,31 @@ public class FlatTextFieldUI
try { try {
FlatUIUtils.setRenderingHints( g2 ); FlatUIUtils.setRenderingHints( g2 );
Color background = focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) ? focusedBackground : c.getBackground(); g2.setColor( getBackground( c, isIntelliJTheme, focusedBackground ) );
g2.setColor( !(background instanceof UIResource)
? background
: (isIntelliJTheme && (!c.isEnabled() || !c.isEditable())
? FlatUIUtils.getParentBackground( c )
: background) );
FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc ); FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc );
} finally { } finally {
g2.dispose(); g2.dispose();
} }
} }
static Color getBackground( JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) {
Color background = c.getBackground();
// always use explicitly set color
if( !(background instanceof UIResource) )
return background;
// for compatibility with IntelliJ themes
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) )
return FlatUIUtils.getParentBackground( c );
// focused and editable
if( focusedBackground != null && c.isEditable() && FlatUIUtils.isPermanentFocusOwner( c ) )
return focusedBackground;
return background;
}
static void paintPlaceholder( Graphics g, JTextComponent c, Color placeholderForeground ) { static void paintPlaceholder( Graphics g, JTextComponent c, Color placeholderForeground ) {
// check whether text component is empty // check whether text component is empty
if( c.getDocument().getLength() > 0 ) if( c.getDocument().getLength() > 0 )

View File

@@ -16,17 +16,17 @@
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.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
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.UIResource;
import javax.swing.plaf.basic.BasicTextPaneUI; import javax.swing.plaf.basic.BasicTextPaneUI;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
/** /**
@@ -51,6 +51,7 @@ import com.formdev.flatlaf.util.HiDPIUtils;
* *
* @uiDefault Component.minimumWidth int * @uiDefault Component.minimumWidth int
* @uiDefault Component.isIntelliJTheme boolean * @uiDefault Component.isIntelliJTheme boolean
* @uiDefault TextPane.focusedBackground Color optional
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -59,8 +60,10 @@ public class FlatTextPaneUI
{ {
protected int minimumWidth; protected int minimumWidth;
protected boolean isIntelliJTheme; protected boolean isIntelliJTheme;
protected Color focusedBackground;
private Object oldHonorDisplayProperties; private Object oldHonorDisplayProperties;
private FocusListener focusListener;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatTextPaneUI(); return new FlatTextPaneUI();
@@ -70,8 +73,10 @@ public class FlatTextPaneUI
protected void installDefaults() { protected void installDefaults() {
super.installDefaults(); super.installDefaults();
String prefix = getPropertyPrefix();
minimumWidth = UIManager.getInt( "Component.minimumWidth" ); minimumWidth = UIManager.getInt( "Component.minimumWidth" );
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
// use component font and foreground for HTML text // use component font and foreground for HTML text
oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES ); oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES );
@@ -82,9 +87,28 @@ public class FlatTextPaneUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
focusedBackground = null;
getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties ); getComponent().putClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES, oldHonorDisplayProperties );
} }
@Override
protected void installListeners() {
super.installListeners();
// necessary to update focus background
focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), c -> focusedBackground != null );
getComponent().addFocusListener( focusListener );
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
getComponent().removeFocusListener( focusListener );
focusListener = null;
}
@Override @Override
protected void propertyChange( PropertyChangeEvent e ) { protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e ); super.propertyChange( e );
@@ -108,14 +132,6 @@ public class FlatTextPaneUI
@Override @Override
protected void paintBackground( Graphics g ) { protected void paintBackground( Graphics g ) {
JTextComponent c = getComponent(); FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
// for compatibility with IntelliJ themes
if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) {
FlatUIUtils.paintParentBackground( g, c );
return;
}
super.paintBackground( g );
} }
} }

View File

@@ -837,19 +837,23 @@ debug*/
implements FocusListener implements FocusListener
{ {
private final Component repaintComponent; private final Component repaintComponent;
private final Predicate<Component> repaintCondition;
public RepaintFocusListener( Component repaintComponent ) { public RepaintFocusListener( Component repaintComponent, Predicate<Component> repaintCondition ) {
this.repaintComponent = repaintComponent; this.repaintComponent = repaintComponent;
this.repaintCondition = repaintCondition;
} }
@Override @Override
public void focusGained( FocusEvent e ) { public void focusGained( FocusEvent e ) {
repaintComponent.repaint(); if( repaintCondition == null || repaintCondition.test( repaintComponent ) )
repaintComponent.repaint();
} }
@Override @Override
public void focusLost( FocusEvent e ) { public void focusLost( FocusEvent e ) {
repaintComponent.repaint(); if( repaintCondition == null || repaintCondition.test( repaintComponent ) )
repaintComponent.repaint();
} }
} }
} }

View File

@@ -156,7 +156,7 @@ public class FlatDatePickerUI
editor.setName( "dateField" ); editor.setName( "dateField" );
editor.setBorder( BorderFactory.createEmptyBorder() ); editor.setBorder( BorderFactory.createEmptyBorder() );
editor.setOpaque( false ); editor.setOpaque( false );
editor.addFocusListener( new FlatUIUtils.RepaintFocusListener( datePicker ) ); editor.addFocusListener( new FlatUIUtils.RepaintFocusListener( datePicker, null ) );
return editor; return editor;
} }

View File

@@ -152,6 +152,16 @@ Desktop.background = #afe
DesktopIcon.background = darken($Desktop.background,20%) DesktopIcon.background = darken($Desktop.background,20%)
#---- EditorPane ----
EditorPane.focusedBackground = #ff8
#---- FormattedTextField ----
FormattedTextField.focusedBackground = #ff8
#---- HelpButton ---- #---- HelpButton ----
HelpButton.focusedBackground = #0ff HelpButton.focusedBackground = #0ff
@@ -223,6 +233,11 @@ OptionPane.icon.warningColor = #fc0
OptionPane.icon.foreground = #fff OptionPane.icon.foreground = #fff
#---- PasswordField ----
PasswordField.focusedBackground = #ff8
#---- Popup ---- #---- Popup ----
Popup.dropShadowColor = #0f0 Popup.dropShadowColor = #0f0
@@ -332,6 +347,21 @@ TableHeader.separatorColor = #0f0
TableHeader.bottomSeparatorColor = #0f0 TableHeader.bottomSeparatorColor = #0f0
#---- TextArea ----
TextArea.focusedBackground = #ff8
#---- TextField ----
TextField.focusedBackground = #ff8
#---- TextPane ----
TextPane.focusedBackground = #ff8
#---- TitledBorder ---- #---- TitledBorder ----
TitledBorder.titleColor = #f0f TitledBorder.titleColor = #f0f