From 26250e790f70dfbd459764145e54c7febb9e99c0 Mon Sep 17 00:00:00 2001 From: Christopher Deckers Date: Tue, 8 Jun 2021 10:12:59 +0200 Subject: [PATCH 1/5] Issue #335: allow a different background on focus. --- .../com/formdev/flatlaf/ui/FlatComboBoxUI.java | 18 ++++++++++++++++-- .../flatlaf/ui/FlatPasswordFieldUI.java | 6 +++++- .../com/formdev/flatlaf/ui/FlatTextAreaUI.java | 10 ++++++++++ .../formdev/flatlaf/ui/FlatTextFieldUI.java | 10 +++++++--- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index f1b7b948..89c72d0c 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java @@ -92,10 +92,12 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault Component.borderColor Color * @uiDefault Component.disabledBorderColor Color * @uiDefault ComboBox.editableBackground Color optional; defaults to ComboBox.background + * @uiDefault ComboBox.focusedBackground Color optional * @uiDefault ComboBox.disabledBackground Color * @uiDefault ComboBox.disabledForeground Color * @uiDefault ComboBox.buttonBackground Color * @uiDefault ComboBox.buttonEditableBackground Color + * @uiDefault ComboBox.buttonFocusedBackground Color optional * @uiDefault ComboBox.buttonArrowColor Color * @uiDefault ComboBox.buttonDisabledArrowColor Color * @uiDefault ComboBox.buttonHoverArrowColor Color @@ -116,10 +118,12 @@ public class FlatComboBoxUI protected Color editableBackground; protected Color disabledBackground; + protected Color focusedBackground; protected Color disabledForeground; protected Color buttonBackground; protected Color buttonEditableBackground; + protected Color buttonFocusedBackground; protected Color buttonArrowColor; protected Color buttonDisabledArrowColor; protected Color buttonHoverArrowColor; @@ -196,9 +200,11 @@ public class FlatComboBoxUI editableBackground = UIManager.getColor( "ComboBox.editableBackground" ); disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" ); + focusedBackground = UIManager.getColor( "ComboBox.focusedBackground" ); disabledForeground = UIManager.getColor( "ComboBox.disabledForeground" ); buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" ); + buttonFocusedBackground = UIManager.getColor( "ComboBox.buttonFocusedBackground" ); buttonEditableBackground = UIManager.getColor( "ComboBox.buttonEditableBackground" ); buttonArrowColor = UIManager.getColor( "ComboBox.buttonArrowColor" ); buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" ); @@ -225,10 +231,12 @@ public class FlatComboBoxUI editableBackground = null; disabledBackground = null; + focusedBackground = null; disabledForeground = null; buttonBackground = null; buttonEditableBackground = null; + buttonFocusedBackground = null; buttonArrowColor = null; buttonDisabledArrowColor = null; buttonHoverArrowColor = null; @@ -423,7 +431,7 @@ public class FlatComboBoxUI // paint arrow button background if( enabled && !isCellRenderer ) { - g2.setColor( paintButton ? buttonEditableBackground : buttonBackground ); + g2.setColor( paintButton ? buttonEditableBackground : buttonFocusedBackground != null && isFocusOwner() ? buttonFocusedBackground : buttonBackground ); Shape oldClip = g2.getClip(); if( isLeftToRight ) g2.clipRect( arrowX, 0, width - arrowX, height ); @@ -484,9 +492,15 @@ public class FlatComboBoxUI protected Color getBackground( boolean enabled ) { return enabled - ? (editableBackground != null && comboBox.isEditable() ? editableBackground : comboBox.getBackground()) + ? (focusedBackground != null && isFocusOwner() + ? focusedBackground + : (editableBackground != null && comboBox.isEditable() ? editableBackground : comboBox.getBackground()) ) : (isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground); } + + protected boolean isFocusOwner() { + return FlatUIUtils.isPermanentFocusOwner( comboBox ) || comboBox.getEditor() != null && comboBox.getEditor().getEditorComponent() != null && FlatUIUtils.isPermanentFocusOwner( comboBox.getEditor().getEditorComponent() ); + } protected Color getForeground( boolean enabled ) { return enabled ? comboBox.getForeground() : disabledForeground; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java index 99c3ac8f..5d279e67 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java @@ -50,6 +50,7 @@ import com.formdev.flatlaf.util.HiDPIUtils; * @uiDefault PasswordField.disabledBackground Color used if not enabled * @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.focusedBackground Color optional * @uiDefault PasswordField.border Border * @uiDefault PasswordField.margin Insets * @uiDefault PasswordField.echoChar character @@ -73,6 +74,7 @@ public class FlatPasswordFieldUI protected int minimumWidth; protected boolean isIntelliJTheme; protected Color placeholderForeground; + protected Color focusedBackground; protected boolean showCapsLock; protected Icon capsLockIcon; @@ -91,6 +93,7 @@ public class FlatPasswordFieldUI minimumWidth = UIManager.getInt( "Component.minimumWidth" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" ); + focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" ); capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" ); @@ -104,6 +107,7 @@ public class FlatPasswordFieldUI super.uninstallDefaults(); placeholderForeground = null; + focusedBackground = null; capsLockIcon = null; MigLayoutVisualPadding.uninstall( getComponent() ); @@ -157,7 +161,7 @@ public class FlatPasswordFieldUI @Override protected void paintSafely( Graphics g ) { - FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme ); + FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground ); FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground ); paintCapsLock( g ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java index 9254749f..fcb440c3 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java @@ -42,6 +42,7 @@ import com.formdev.flatlaf.util.HiDPIUtils; * @uiDefault TextArea.selectionBackground Color * @uiDefault TextArea.selectionForeground Color * @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.margin Insets * @uiDefault TextArea.caretBlinkRate int default is 500 milliseconds @@ -63,6 +64,7 @@ public class FlatTextAreaUI protected Color background; protected Color disabledBackground; protected Color inactiveBackground; + protected Color focusedBackground; public static ComponentUI createUI( JComponent c ) { return new FlatTextAreaUI(); @@ -84,6 +86,7 @@ public class FlatTextAreaUI background = UIManager.getColor( "TextArea.background" ); disabledBackground = UIManager.getColor( "TextArea.disabledBackground" ); inactiveBackground = UIManager.getColor( "TextArea.inactiveBackground" ); + focusedBackground = UIManager.getColor( "TextArea.focusedBackground" ); } @Override @@ -93,6 +96,7 @@ public class FlatTextAreaUI background = null; disabledBackground = null; inactiveBackground = null; + focusedBackground = null; } @Override @@ -164,6 +168,12 @@ public class FlatTextAreaUI return; } + if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) ) { + g.setColor( focusedBackground ); + g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); + return; + } + super.paintBackground( g ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java index 572a0298..90e78f05 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java @@ -55,6 +55,7 @@ import com.formdev.flatlaf.util.JavaCompatibility; * @uiDefault TextField.disabledBackground Color used if not enabled * @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.focusedBackground Color optional * @uiDefault TextField.border Border * @uiDefault TextField.margin Insets * @uiDefault TextField.caretBlinkRate int default is 500 milliseconds @@ -75,6 +76,7 @@ public class FlatTextFieldUI protected int minimumWidth; protected boolean isIntelliJTheme; protected Color placeholderForeground; + protected Color focusedBackground; private FocusListener focusListener; @@ -90,6 +92,7 @@ public class FlatTextFieldUI minimumWidth = UIManager.getInt( "Component.minimumWidth" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" ); + focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); LookAndFeel.installProperty( getComponent(), "opaque", false ); @@ -101,6 +104,7 @@ public class FlatTextFieldUI super.uninstallDefaults(); placeholderForeground = null; + focusedBackground = null; MigLayoutVisualPadding.uninstall( getComponent() ); } @@ -148,7 +152,7 @@ public class FlatTextFieldUI @Override protected void paintSafely( Graphics g ) { - paintBackground( g, getComponent(), isIntelliJTheme ); + paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground ); paintPlaceholder( g, getComponent(), placeholderForeground ); super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) ); @@ -159,7 +163,7 @@ public class FlatTextFieldUI // background is painted elsewhere } - static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme ) { + static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) { // do not paint background if: // - not opaque and // - border is not a flat border and @@ -180,7 +184,7 @@ public class FlatTextFieldUI try { FlatUIUtils.setRenderingHints( g2 ); - Color background = c.getBackground(); + Color background = focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) ? focusedBackground : c.getBackground(); g2.setColor( !(background instanceof UIResource) ? background : (isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) From b99fb8b11f7dd6cdffc6fa66a085102b4e778d01 Mon Sep 17 00:00:00 2001 From: Christopher Deckers Date: Tue, 8 Jun 2021 14:19:17 +0200 Subject: [PATCH 2/5] Use focused background color for combo popups. --- .../src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index 89c72d0c..6f4e2e3d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java @@ -702,6 +702,9 @@ public class FlatComboBoxUI super.configureList(); list.setCellRenderer( new PopupListCellRenderer() ); + if( focusedBackground != null ) { + list.setBackground( focusedBackground ); + } } @Override From a51294d57082538a33e3b45e8c8182486660aecf Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 12 Jun 2021 20:46:59 +0200 Subject: [PATCH 3/5] 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) --- .../formdev/flatlaf/ui/FlatEditorPaneUI.java | 40 ++++++++++++++----- .../flatlaf/ui/FlatFormattedTextFieldUI.java | 1 + .../flatlaf/ui/FlatPasswordFieldUI.java | 7 +++- .../formdev/flatlaf/ui/FlatTextAreaUI.java | 38 ++++++++++-------- .../formdev/flatlaf/ui/FlatTextFieldUI.java | 30 ++++++++++---- .../formdev/flatlaf/ui/FlatTextPaneUI.java | 38 +++++++++++++----- .../com/formdev/flatlaf/ui/FlatUIUtils.java | 10 +++-- .../flatlaf/swingx/ui/FlatDatePickerUI.java | 2 +- .../flatlaf/testing/FlatTestLaf.properties | 30 ++++++++++++++ 9 files changed, 146 insertions(+), 50 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatEditorPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatEditorPaneUI.java index 45484034..0179e60d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatEditorPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatEditorPaneUI.java @@ -17,15 +17,16 @@ package com.formdev.flatlaf.ui; import static com.formdev.flatlaf.util.UIScale.scale; +import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicEditorPaneUI; import javax.swing.text.JTextComponent; import com.formdev.flatlaf.FlatClientProperties; @@ -53,6 +54,7 @@ import com.formdev.flatlaf.util.HiDPIUtils; * * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean + * @uiDefault EditorPane.focusedBackground Color optional * * @author Karl Tauber */ @@ -61,8 +63,10 @@ public class FlatEditorPaneUI { protected int minimumWidth; protected boolean isIntelliJTheme; + protected Color focusedBackground; private Object oldHonorDisplayProperties; + private FocusListener focusListener; public static ComponentUI createUI( JComponent c ) { return new FlatEditorPaneUI(); @@ -72,8 +76,10 @@ public class FlatEditorPaneUI protected void installDefaults() { super.installDefaults(); + String prefix = getPropertyPrefix(); minimumWidth = UIManager.getInt( "Component.minimumWidth" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); + focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); // use component font and foreground for HTML text oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES ); @@ -84,9 +90,28 @@ public class FlatEditorPaneUI protected void uninstallDefaults() { super.uninstallDefaults(); + focusedBackground = null; + 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 protected void propertyChange( PropertyChangeEvent e ) { super.propertyChange( e ); @@ -128,14 +153,11 @@ public class FlatEditorPaneUI @Override protected void paintBackground( Graphics g ) { - JTextComponent c = getComponent(); + 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 ); + static void paintBackground( Graphics g, JTextComponent c, boolean isIntelliJTheme, Color focusedBackground ) { + g.setColor( FlatTextFieldUI.getBackground( c, isIntelliJTheme, focusedBackground ) ); + g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java index 8b5f47e1..11d91245 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java @@ -44,6 +44,7 @@ import javax.swing.plaf.ComponentUI; * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean * @uiDefault FormattedTextField.placeholderForeground Color + * @uiDefault FormattedTextField.focusedBackground Color optional * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * @uiDefault TextComponent.selectAllOnMouseClick boolean * diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java index 5d279e67..d338aa53 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPasswordFieldUI.java @@ -50,7 +50,6 @@ import com.formdev.flatlaf.util.HiDPIUtils; * @uiDefault PasswordField.disabledBackground Color used if not enabled * @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.focusedBackground Color optional * @uiDefault PasswordField.border Border * @uiDefault PasswordField.margin Insets * @uiDefault PasswordField.echoChar character @@ -61,6 +60,7 @@ import com.formdev.flatlaf.util.HiDPIUtils; * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean * @uiDefault PasswordField.placeholderForeground Color + * @uiDefault PasswordField.focusedBackground Color optional * @uiDefault PasswordField.showCapsLock boolean * @uiDefault PasswordField.capsLockIcon Icon * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always @@ -117,7 +117,10 @@ public class FlatPasswordFieldUI protected void 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() { @Override public void keyPressed( KeyEvent e ) { diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java index fcb440c3..21824be5 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextAreaUI.java @@ -20,6 +20,7 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; import javax.swing.JComponent; import javax.swing.JTextArea; @@ -42,7 +43,6 @@ import com.formdev.flatlaf.util.HiDPIUtils; * @uiDefault TextArea.selectionBackground Color * @uiDefault TextArea.selectionForeground Color * @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.margin Insets * @uiDefault TextArea.caretBlinkRate int default is 500 milliseconds @@ -53,6 +53,7 @@ import com.formdev.flatlaf.util.HiDPIUtils; * @uiDefault Component.isIntelliJTheme boolean * @uiDefault TextArea.disabledBackground Color used if not enabled * @uiDefault TextArea.inactiveBackground Color used if not editable + * @uiDefault TextArea.focusedBackground Color optional * * @author Karl Tauber */ @@ -66,6 +67,8 @@ public class FlatTextAreaUI protected Color inactiveBackground; protected Color focusedBackground; + private FocusListener focusListener; + public static ComponentUI createUI( JComponent c ) { return new FlatTextAreaUI(); } @@ -99,6 +102,23 @@ public class FlatTextAreaUI 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 protected void propertyChange( PropertyChangeEvent e ) { super.propertyChange( e ); @@ -160,20 +180,6 @@ public class FlatTextAreaUI @Override protected void paintBackground( Graphics g ) { - JTextComponent c = getComponent(); - - // 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 ); + FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java index 90e78f05..d80ac851 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java @@ -55,7 +55,6 @@ import com.formdev.flatlaf.util.JavaCompatibility; * @uiDefault TextField.disabledBackground Color used if not enabled * @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.focusedBackground Color optional * @uiDefault TextField.border Border * @uiDefault TextField.margin Insets * @uiDefault TextField.caretBlinkRate int default is 500 milliseconds @@ -65,6 +64,7 @@ import com.formdev.flatlaf.util.JavaCompatibility; * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean * @uiDefault TextField.placeholderForeground Color + * @uiDefault TextField.focusedBackground Color optional * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * @uiDefault TextComponent.selectAllOnMouseClick boolean * @@ -113,7 +113,8 @@ public class FlatTextFieldUI protected void installListeners() { super.installListeners(); - focusListener = new FlatUIUtils.RepaintFocusListener( getComponent() ); + // necessary to update focus border and background + focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null ); getComponent().addFocusListener( focusListener ); } @@ -184,18 +185,31 @@ public class FlatTextFieldUI try { FlatUIUtils.setRenderingHints( g2 ); - Color background = focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) ? focusedBackground : c.getBackground(); - g2.setColor( !(background instanceof UIResource) - ? background - : (isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) - ? FlatUIUtils.getParentBackground( c ) - : background) ); + g2.setColor( getBackground( c, isIntelliJTheme, focusedBackground ) ); FlatUIUtils.paintComponentBackground( g2, 0, 0, c.getWidth(), c.getHeight(), focusWidth, arc ); } finally { 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 ) { // check whether text component is empty if( c.getDocument().getLength() > 0 ) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextPaneUI.java index 0def747f..0da0c538 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextPaneUI.java @@ -16,17 +16,17 @@ package com.formdev.flatlaf.ui; +import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicTextPaneUI; -import javax.swing.text.JTextComponent; import com.formdev.flatlaf.util.HiDPIUtils; /** @@ -51,6 +51,7 @@ import com.formdev.flatlaf.util.HiDPIUtils; * * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean + * @uiDefault TextPane.focusedBackground Color optional * * @author Karl Tauber */ @@ -59,8 +60,10 @@ public class FlatTextPaneUI { protected int minimumWidth; protected boolean isIntelliJTheme; + protected Color focusedBackground; private Object oldHonorDisplayProperties; + private FocusListener focusListener; public static ComponentUI createUI( JComponent c ) { return new FlatTextPaneUI(); @@ -70,8 +73,10 @@ public class FlatTextPaneUI protected void installDefaults() { super.installDefaults(); + String prefix = getPropertyPrefix(); minimumWidth = UIManager.getInt( "Component.minimumWidth" ); isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); + focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); // use component font and foreground for HTML text oldHonorDisplayProperties = getComponent().getClientProperty( JEditorPane.HONOR_DISPLAY_PROPERTIES ); @@ -82,9 +87,28 @@ public class FlatTextPaneUI protected void uninstallDefaults() { super.uninstallDefaults(); + focusedBackground = null; + 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 protected void propertyChange( PropertyChangeEvent e ) { super.propertyChange( e ); @@ -108,14 +132,6 @@ public class FlatTextPaneUI @Override protected void paintBackground( Graphics g ) { - JTextComponent c = getComponent(); - - // for compatibility with IntelliJ themes - if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) && (c.getBackground() instanceof UIResource) ) { - FlatUIUtils.paintParentBackground( g, c ); - return; - } - - super.paintBackground( g ); + FlatEditorPaneUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java index c868af02..8acbdc1e 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java @@ -837,19 +837,23 @@ debug*/ implements FocusListener { private final Component repaintComponent; + private final Predicate repaintCondition; - public RepaintFocusListener( Component repaintComponent ) { + public RepaintFocusListener( Component repaintComponent, Predicate repaintCondition ) { this.repaintComponent = repaintComponent; + this.repaintCondition = repaintCondition; } @Override public void focusGained( FocusEvent e ) { - repaintComponent.repaint(); + if( repaintCondition == null || repaintCondition.test( repaintComponent ) ) + repaintComponent.repaint(); } @Override public void focusLost( FocusEvent e ) { - repaintComponent.repaint(); + if( repaintCondition == null || repaintCondition.test( repaintComponent ) ) + repaintComponent.repaint(); } } } diff --git a/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatDatePickerUI.java b/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatDatePickerUI.java index 7c988d5b..a3a92549 100644 --- a/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatDatePickerUI.java +++ b/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatDatePickerUI.java @@ -156,7 +156,7 @@ public class FlatDatePickerUI editor.setName( "dateField" ); editor.setBorder( BorderFactory.createEmptyBorder() ); editor.setOpaque( false ); - editor.addFocusListener( new FlatUIUtils.RepaintFocusListener( datePicker ) ); + editor.addFocusListener( new FlatUIUtils.RepaintFocusListener( datePicker, null ) ); return editor; } diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties index c6b78bfd..6af9434a 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties @@ -152,6 +152,16 @@ Desktop.background = #afe DesktopIcon.background = darken($Desktop.background,20%) +#---- EditorPane ---- + +EditorPane.focusedBackground = #ff8 + + +#---- FormattedTextField ---- + +FormattedTextField.focusedBackground = #ff8 + + #---- HelpButton ---- HelpButton.focusedBackground = #0ff @@ -223,6 +233,11 @@ OptionPane.icon.warningColor = #fc0 OptionPane.icon.foreground = #fff +#---- PasswordField ---- + +PasswordField.focusedBackground = #ff8 + + #---- Popup ---- Popup.dropShadowColor = #0f0 @@ -332,6 +347,21 @@ TableHeader.separatorColor = #0f0 TableHeader.bottomSeparatorColor = #0f0 +#---- TextArea ---- + +TextArea.focusedBackground = #ff8 + + +#---- TextField ---- + +TextField.focusedBackground = #ff8 + + +#---- TextPane ---- + +TextPane.focusedBackground = #ff8 + + #---- TitledBorder ---- TitledBorder.titleColor = #f0f From 7e0915cb9cd3836288ad1b13f0d5ac8711fca7c0 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 13 Jun 2021 11:21:55 +0200 Subject: [PATCH 4/5] FlatBorder: refractored ComboBox, ScrollPane and Spinner focus owner checking to UI delegates (for later usage) --- .../com/formdev/flatlaf/ui/FlatBorder.java | 43 +++---------------- .../formdev/flatlaf/ui/FlatComboBoxUI.java | 8 ++++ .../formdev/flatlaf/ui/FlatScrollPaneUI.java | 27 ++++++++++++ .../com/formdev/flatlaf/ui/FlatSpinnerUI.java | 10 +++++ 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatBorder.java index df8802ff..27c8d424 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatBorder.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatBorder.java @@ -22,17 +22,12 @@ import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; -import java.awt.KeyboardFocusManager; import java.awt.Paint; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JScrollPane; import javax.swing.JSpinner; -import javax.swing.JTable; -import javax.swing.JTextField; -import javax.swing.JTree; import javax.swing.JViewport; -import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicBorders; import com.formdev.flatlaf.FlatClientProperties; @@ -164,37 +159,13 @@ public class FlatBorder } protected boolean isFocused( Component c ) { - if( c instanceof JScrollPane ) { - JViewport viewport = ((JScrollPane)c).getViewport(); - Component view = (viewport != null) ? viewport.getView() : null; - if( view != null ) { - if( FlatUIUtils.isPermanentFocusOwner( view ) ) - return true; - - if( (view instanceof JTable && ((JTable)view).isEditing()) || - (view instanceof JTree && ((JTree)view).isEditing()) ) - { - Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); - if( focusOwner != null ) - return SwingUtilities.isDescendingFrom( focusOwner, view ); - } - } - return false; - } else if( c instanceof JComboBox && ((JComboBox)c).isEditable() ) { - Component editorComponent = ((JComboBox)c).getEditor().getEditorComponent(); - return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false; - } else if( c instanceof JSpinner ) { - if( FlatUIUtils.isPermanentFocusOwner( c ) ) - return true; - - JComponent editor = ((JSpinner)c).getEditor(); - if( editor instanceof JSpinner.DefaultEditor ) { - JTextField textField = ((JSpinner.DefaultEditor)editor).getTextField(); - if( textField != null ) - return FlatUIUtils.isPermanentFocusOwner( textField ); - } - return false; - } else + if( c instanceof JScrollPane ) + return FlatScrollPaneUI.isPermanentFocusOwner( (JScrollPane) c ); + else if( c instanceof JComboBox ) + return FlatComboBoxUI.isPermanentFocusOwner( (JComboBox) c ); + else if( c instanceof JSpinner ) + return FlatSpinnerUI.isPermanentFocusOwner( (JSpinner) c ); + else return FlatUIUtils.isPermanentFocusOwner( c ); } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index 6f4e2e3d..32de8ea0 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java @@ -590,6 +590,14 @@ public class FlatComboBoxUI return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() ); } + public static boolean isPermanentFocusOwner( JComboBox comboBox ) { + if( comboBox.isEditable() ) { + Component editorComponent = comboBox.getEditor().getEditorComponent(); + return (editorComponent != null) ? FlatUIUtils.isPermanentFocusOwner( editorComponent ) : false; + } else + return FlatUIUtils.isPermanentFocusOwner( comboBox ); + } + //---- class FlatComboBoxButton ------------------------------------------- protected class FlatComboBoxButton diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java index fe2575cb..bd8ba14d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java @@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui; import java.awt.Component; import java.awt.Graphics; import java.awt.Insets; +import java.awt.KeyboardFocusManager; import java.awt.Rectangle; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; @@ -34,11 +35,13 @@ import javax.swing.JComponent; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JTable; +import javax.swing.JTree; import javax.swing.JViewport; import javax.swing.LookAndFeel; import javax.swing.ScrollPaneConstants; import javax.swing.Scrollable; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicScrollPaneUI; @@ -329,6 +332,28 @@ public class FlatScrollPaneUI paint( g, c ); } + public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) { + JViewport viewport = scrollPane.getViewport(); + Component view = (viewport != null) ? viewport.getView() : null; + if( view == null ) + return false; + + // check whether view is focus owner + if( FlatUIUtils.isPermanentFocusOwner( view ) ) + return true; + + // check whether editor component in JTable or JTree is focus owner + if( (view instanceof JTable && ((JTable)view).isEditing()) || + (view instanceof JTree && ((JTree)view).isEditing()) ) + { + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + if( focusOwner != null ) + return SwingUtilities.isDescendingFrom( focusOwner, view ); + } + + return false; + } + //---- class Handler ------------------------------------------------------ /** @@ -350,11 +375,13 @@ public class FlatScrollPaneUI @Override public void focusGained( FocusEvent e ) { + // necessary to update focus border scrollpane.repaint(); } @Override public void focusLost( FocusEvent e ) { + // necessary to update focus border scrollpane.repaint(); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java index 17c826d2..b7d8e4c8 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java @@ -221,6 +221,16 @@ public class FlatSpinnerUI : null; } + public static boolean isPermanentFocusOwner( JSpinner spinner ) { + if( FlatUIUtils.isPermanentFocusOwner( spinner ) ) + return true; + + JTextField textField = getEditorTextField( spinner.getEditor() ); + return (textField != null) + ? FlatUIUtils.isPermanentFocusOwner( textField ) + : false; + } + protected Color getBackground( boolean enabled ) { return enabled ? spinner.getBackground() From ed9cb0f918616cb16dd794c23c8eaffac43de129 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Tue, 15 Jun 2021 11:50:30 +0200 Subject: [PATCH 5/5] Spinner: support Spinner.focusedBackground ComboBox: - prefer explicit set background color over focusedBackground - if ComboBox.buttonFocusedBackground is not specified use ComboBox.focusedBackground - added ComboBox.popupFocusedBackground (issue #335) --- CHANGELOG.md | 13 +++++ .../formdev/flatlaf/ui/FlatComboBoxUI.java | 50 ++++++++++++------- .../com/formdev/flatlaf/ui/FlatSpinnerUI.java | 24 +++++++-- .../flatlaf/testing/FlatTestLaf.properties | 9 ++++ 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cea8f65..2ed6b45d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ FlatLaf Change Log ================== +## 1.3-SNAPSHOT + +#### New features and improvements + +- TextComponents, ComboBox and Spinner: Support different background color when + component is focused (use UI values `TextField.focusedBackground`, + `PasswordField.focusedBackground`, `FormattedTextField.focusedBackground`, + `TextArea.focusedBackground`, `TextPane.focusedBackground`, + `EditorPane.focusedBackground`, `ComboBox.focusedBackground`, + `ComboBox.buttonFocusedBackground`, `ComboBox.popupFocusedBackground` and + `Spinner.focusedBackground`). (issue #335) + + ## 1.2 #### New features and improvements diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index 32de8ea0..1f585521 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java @@ -61,6 +61,7 @@ import javax.swing.UIManager; import javax.swing.border.AbstractBorder; import javax.swing.border.Border; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicComboBoxUI; import javax.swing.plaf.basic.BasicComboPopup; import javax.swing.plaf.basic.ComboPopup; @@ -97,11 +98,12 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault ComboBox.disabledForeground Color * @uiDefault ComboBox.buttonBackground Color * @uiDefault ComboBox.buttonEditableBackground Color - * @uiDefault ComboBox.buttonFocusedBackground Color optional + * @uiDefault ComboBox.buttonFocusedBackground Color optional; defaults to ComboBox.focusedBackground * @uiDefault ComboBox.buttonArrowColor Color * @uiDefault ComboBox.buttonDisabledArrowColor Color * @uiDefault ComboBox.buttonHoverArrowColor Color * @uiDefault ComboBox.buttonPressedArrowColor Color + * @uiDefault ComboBox.popupFocusedBackground Color optional * * @author Karl Tauber */ @@ -117,8 +119,8 @@ public class FlatComboBoxUI protected Color disabledBorderColor; protected Color editableBackground; - protected Color disabledBackground; protected Color focusedBackground; + protected Color disabledBackground; protected Color disabledForeground; protected Color buttonBackground; @@ -129,6 +131,8 @@ public class FlatComboBoxUI protected Color buttonHoverArrowColor; protected Color buttonPressedArrowColor; + protected Color popupFocusedBackground; + private MouseListener hoverListener; protected boolean hover; protected boolean pressed; @@ -199,8 +203,8 @@ public class FlatComboBoxUI disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" ); editableBackground = UIManager.getColor( "ComboBox.editableBackground" ); - disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" ); focusedBackground = UIManager.getColor( "ComboBox.focusedBackground" ); + disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" ); disabledForeground = UIManager.getColor( "ComboBox.disabledForeground" ); buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" ); @@ -211,6 +215,8 @@ public class FlatComboBoxUI buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" ); buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" ); + popupFocusedBackground = UIManager.getColor( "ComboBox.popupFocusedBackground" ); + // set maximumRowCount int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" ); if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 ) @@ -230,8 +236,8 @@ public class FlatComboBoxUI disabledBorderColor = null; editableBackground = null; - disabledBackground = null; focusedBackground = null; + disabledBackground = null; disabledForeground = null; buttonBackground = null; @@ -242,6 +248,8 @@ public class FlatComboBoxUI buttonHoverArrowColor = null; buttonPressedArrowColor = null; + popupFocusedBackground = null; + MigLayoutVisualPadding.uninstall( comboBox ); } @@ -431,7 +439,11 @@ public class FlatComboBoxUI // paint arrow button background if( enabled && !isCellRenderer ) { - g2.setColor( paintButton ? buttonEditableBackground : buttonFocusedBackground != null && isFocusOwner() ? buttonFocusedBackground : buttonBackground ); + g2.setColor( paintButton + ? buttonEditableBackground + : (buttonFocusedBackground != null || focusedBackground != null) && isPermanentFocusOwner( comboBox ) + ? (buttonFocusedBackground != null ? buttonFocusedBackground : focusedBackground) + : buttonBackground ); Shape oldClip = g2.getClip(); if( isLeftToRight ) g2.clipRect( arrowX, 0, width - arrowX, height ); @@ -491,15 +503,20 @@ public class FlatComboBoxUI } protected Color getBackground( boolean enabled ) { - return enabled - ? (focusedBackground != null && isFocusOwner() - ? focusedBackground - : (editableBackground != null && comboBox.isEditable() ? editableBackground : comboBox.getBackground()) ) - : (isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground); - } - - protected boolean isFocusOwner() { - return FlatUIUtils.isPermanentFocusOwner( comboBox ) || comboBox.getEditor() != null && comboBox.getEditor().getEditorComponent() != null && FlatUIUtils.isPermanentFocusOwner( comboBox.getEditor().getEditorComponent() ); + if( enabled ) { + Color background = comboBox.getBackground(); + + // always use explicitly set color + if( !(background instanceof UIResource) ) + return background; + + // focused + if( focusedBackground != null && isPermanentFocusOwner( comboBox ) ) + return focusedBackground; + + return (editableBackground != null && comboBox.isEditable()) ? editableBackground : background; + } else + return isIntelliJTheme ? FlatUIUtils.getParentBackground( comboBox ) : disabledBackground; } protected Color getForeground( boolean enabled ) { @@ -710,9 +727,8 @@ public class FlatComboBoxUI super.configureList(); list.setCellRenderer( new PopupListCellRenderer() ); - if( focusedBackground != null ) { - list.setBackground( focusedBackground ); - } + if( popupFocusedBackground != null ) + list.setBackground( popupFocusedBackground ); } @Override diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java index b7d8e4c8..a341d0a9 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java @@ -39,6 +39,7 @@ import javax.swing.LookAndFeel; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicSpinnerUI; import com.formdev.flatlaf.FlatClientProperties; @@ -65,6 +66,7 @@ import com.formdev.flatlaf.FlatClientProperties; * @uiDefault Component.disabledBorderColor Color * @uiDefault Spinner.disabledBackground Color * @uiDefault Spinner.disabledForeground Color + * @uiDefault Spinner.focusedBackground Color optional * @uiDefault Spinner.buttonBackground Color * @uiDefault Spinner.buttonArrowColor Color * @uiDefault Spinner.buttonDisabledArrowColor Color @@ -87,6 +89,7 @@ public class FlatSpinnerUI protected Color disabledBorderColor; protected Color disabledBackground; protected Color disabledForeground; + protected Color focusedBackground; protected Color buttonBackground; protected Color buttonArrowColor; protected Color buttonDisabledArrowColor; @@ -112,6 +115,7 @@ public class FlatSpinnerUI disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" ); disabledBackground = UIManager.getColor( "Spinner.disabledBackground" ); disabledForeground = UIManager.getColor( "Spinner.disabledForeground" ); + focusedBackground = UIManager.getColor( "Spinner.focusedBackground" ); buttonBackground = UIManager.getColor( "Spinner.buttonBackground" ); buttonArrowColor = UIManager.getColor( "Spinner.buttonArrowColor" ); buttonDisabledArrowColor = UIManager.getColor( "Spinner.buttonDisabledArrowColor" ); @@ -133,6 +137,7 @@ public class FlatSpinnerUI disabledBorderColor = null; disabledBackground = null; disabledForeground = null; + focusedBackground = null; buttonBackground = null; buttonArrowColor = null; buttonDisabledArrowColor = null; @@ -232,9 +237,20 @@ public class FlatSpinnerUI } protected Color getBackground( boolean enabled ) { - return enabled - ? spinner.getBackground() - : (isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground); + if( enabled ) { + Color background = spinner.getBackground(); + + // always use explicitly set color + if( !(background instanceof UIResource) ) + return background; + + // focused + if( focusedBackground != null && isPermanentFocusOwner( spinner ) ) + return focusedBackground; + + return background; + } else + return isIntelliJTheme ? FlatUIUtils.getParentBackground( spinner ) : disabledBackground; } protected Color getForeground( boolean enabled ) { @@ -415,6 +431,7 @@ public class FlatSpinnerUI @Override public void focusGained( FocusEvent e ) { + // necessary to update focus border spinner.repaint(); // if spinner gained focus, transfer it to the editor text field @@ -427,6 +444,7 @@ public class FlatSpinnerUI @Override public void focusLost( FocusEvent e ) { + // necessary to update focus border spinner.repaint(); } diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties index 6af9434a..cc4d76a7 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties @@ -130,6 +130,10 @@ ComboBox.background = #fff ComboBox.buttonBackground = #f0f0f0 ComboBox.buttonEditableBackground = #ccc +ComboBox.focusedBackground = #ff8 +ComboBox.buttonFocusedBackground = #ff0 +ComboBox.popupFocusedBackground = #ffc + #---- Component ---- @@ -295,6 +299,11 @@ Slider.disabledTrackColor = #ff8 Slider.disabledThumbColor = #880 +#---- Spinner ---- + +Spinner.focusedBackground = #ff8 + + #---- SplitPane ---- SplitPaneDivider.draggingColor = #800