diff --git a/CHANGELOG.md b/CHANGELOG.md
index 435808d2..1b91df39 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,12 +28,18 @@ FlatLaf Change Log
setting UI default `OptionPane.showIcon` to `true`. (issue #416)
- No longer show the Java "duke/cup" icon if no window icon image is set.
(issue #416)
-- TextField, FormattedTextField and PasswordField: Support leading and trailing
- icons (set client property `JTextField.leadingIcon` or
- `JTextField.trailingIcon` to a `javax.swing.Icon`). (PR #378; issue #368)
-- TextField, FormattedTextField and PasswordField: Support leading and trailing
- components (set client property `JTextField.leadingComponent` or
- `JTextField.trailingComponent` to a `java.awt.Component`). (PR #386)
+- TextField, FormattedTextField and PasswordField:
+ - Support leading and trailing icons (set client property
+ `JTextField.leadingIcon` or `JTextField.trailingIcon` to a
+ `javax.swing.Icon`). (PR #378; issue #368)
+ - Support leading and trailing components (set client property
+ `JTextField.leadingComponent` or `JTextField.trailingComponent` to a
+ `java.awt.Component`). (PR #386)
+ - Support "clear" (or "cancel") button to empty text field. Only shown if text
+ field is not empty, editable and enabled. (set client property
+ `JTextField.showClearButton` to `true`). (PR #442)
+- PasswordField: Support reveal (or "eye") button to show password. (see UI
+ value `PasswordField.showRevealButton`) (PR #442; issue #173)
- TextComponents: Double/triple-click-and-drag now extends selection by whole
words/lines.
- Theming improvements: Reworks core themes to make it easier to create new
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java
index dd5e1242..4f398439 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java
@@ -903,6 +903,47 @@ public interface FlatClientProperties
*/
String TEXT_FIELD_TRAILING_COMPONENT = "JTextField.trailingComponent";
+ /**
+ * Specifies whether a "clear" (or "cancel") button is shown on the trailing side
+ * if the text field is not empty, editable and enabled. Default is {@code false}.
+ *
+ * Component {@link javax.swing.JTextField} (and subclasses)
+ * Value type {@link java.lang.Boolean}
+ *
+ * @since 2
+ */
+ String TEXT_FIELD_SHOW_CLEAR_BUTTON = "JTextField.showClearButton";
+
+ /**
+ * Specifies the callback that is invoked when a "clear" (or "cancel") button is clicked.
+ * If a callback is specified than it is responsible for clearing the text field.
+ * Without callback, the text field clears itself.
+ *
+ * Either use a {@link java.lang.Runnable}:
+ *
{@code
+ * myTextField.putClientProperty( "JTextField.clearCallback",
+ * (Runnable) () -> {
+ * // clear field here or cancel search
+ * } );
+ * }
+ * Or use a {@link java.util.function.Consumer}<javax.swing.text.JTextComponent>
+ * that receives the text field as parameter:
+ * {@code
+ * myTextField.putClientProperty( "JTextField.clearCallback",
+ * (Consumer) textField -> {
+ * // clear field here or cancel search
+ * } );
+ * }
+ *
+ * Component {@link javax.swing.JTextField} (and subclasses)
+ * Value type {@link java.lang.Runnable}
+ * or {@link java.util.function.Consumer}<javax.swing.text.JTextComponent>
+ *
+ * @see #TEXT_FIELD_SHOW_CLEAR_BUTTON
+ * @since 2
+ */
+ String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback";
+
//---- JToggleButton ------------------------------------------------------
/**
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatRevealIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatRevealIcon.java
new file mode 100644
index 00000000..8956e129
--- /dev/null
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatRevealIcon.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 FormDev Software GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.formdev.flatlaf.icons;
+
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+import javax.swing.UIManager;
+
+/**
+ * "eye" icon for {@link javax.swing.JPasswordField}.
+ *
+ * @uiDefault PasswordField.revealIconColor Color
+ *
+ * @author Karl Tauber
+ * @since 2
+ */
+public class FlatRevealIcon
+ extends FlatAbstractIcon
+{
+ public FlatRevealIcon() {
+ super( 16, 16, UIManager.getColor( "PasswordField.revealIconColor" ) );
+ }
+
+ @Override
+ protected void paintIcon( Component c, Graphics2D g ) {
+ Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
+ path.append( new Ellipse2D.Float( 5.15f, 6.15f, 5.7f, 5.7f ), false );
+ path.append( new Ellipse2D.Float( 6, 7, 4, 4 ), false );
+ g.fill( path );
+
+ Path2D path2 = new Path2D.Float( Path2D.WIND_EVEN_ODD );
+ path2.append( new Ellipse2D.Float( 2.15f, 4.15f, 11.7f, 11.7f ), false );
+ path2.append( new Ellipse2D.Float( 3, 5, 10, 10 ), false );
+ Area area = new Area( path2 );
+ area.subtract( new Area( new Rectangle2D.Float( 0, 9.5f, 16, 16 ) ) );
+ g.fill( area );
+ }
+}
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 69c93889..5d5fc82d 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
@@ -28,6 +28,7 @@ import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.Icon;
import javax.swing.JComponent;
+import javax.swing.JToggleButton;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
@@ -73,18 +74,25 @@ import com.formdev.flatlaf.util.UIScale;
*
* @uiDefault PasswordField.echoChar character
* @uiDefault PasswordField.showCapsLock boolean
+ * @uiDefault PasswordField.showRevealButton boolean
* @uiDefault PasswordField.capsLockIcon Icon
+ * @uiDefault PasswordField.revealIcon Icon
*
* @author Karl Tauber
*/
public class FlatPasswordFieldUI
extends FlatTextFieldUI
{
+ private Character echoChar;
+
@Styleable protected boolean showCapsLock;
+ /** @since 2 */ @Styleable protected boolean showRevealButton;
protected Icon capsLockIcon;
+ /** @since 2 */ protected Icon revealIcon;
private KeyListener capsLockListener;
private boolean capsLockIconShared = true;
+ private JToggleButton revealButton;
public static ComponentUI createUI( JComponent c ) {
return new FlatPasswordFieldUI();
@@ -95,17 +103,33 @@ public class FlatPasswordFieldUI
return "PasswordField";
}
+ @Override
+ public void installUI( JComponent c ) {
+ super.installUI( c );
+
+ installRevealButton();
+ }
+
+ @Override
+ public void uninstallUI( JComponent c ) {
+ uninstallRevealButton();
+
+ super.uninstallUI( c );
+ }
+
@Override
protected void installDefaults() {
super.installDefaults();
String prefix = getPropertyPrefix();
- Character echoChar = (Character) UIManager.get( prefix + ".echoChar" );
+ echoChar = (Character) UIManager.get( prefix + ".echoChar" );
if( echoChar != null )
LookAndFeel.installProperty( getComponent(), "echoChar", echoChar );
showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" );
+ showRevealButton = UIManager.getBoolean( "PasswordField.showRevealButton" );
capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" );
+ revealIcon = UIManager.getIcon( "PasswordField.revealIcon" );
capsLockIconShared = true;
}
@@ -114,6 +138,7 @@ public class FlatPasswordFieldUI
super.uninstallDefaults();
capsLockIcon = null;
+ revealIcon = null;
}
@Override
@@ -168,6 +193,18 @@ public class FlatPasswordFieldUI
return "PasswordField";
}
+ @Override
+ protected void applyStyle( Object style ) {
+ boolean oldShowRevealButton = showRevealButton;
+
+ super.applyStyle( style );
+
+ if( showRevealButton != oldShowRevealButton ) {
+ uninstallRevealButton();
+ installRevealButton();
+ }
+ }
+
/** @since 2 */
@Override
protected Object applyStyleProperty( String key, Object value ) {
@@ -236,4 +273,39 @@ public class FlatPasswordFieldUI
return FlatUIUtils.isPermanentFocusOwner( c ) &&
Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK );
}
+
+ /** @since 2 */
+ protected void installRevealButton() {
+ JTextComponent c = getComponent();
+ if( showRevealButton ) {
+ revealButton = createRevealButton();
+ installLayout();
+ c.add( revealButton );
+ }
+ }
+
+ /** @since 2 */
+ protected JToggleButton createRevealButton() {
+ JToggleButton button = new JToggleButton( revealIcon );
+ prepareLeadingOrTrailingComponent( button );
+ button.addActionListener( e -> {
+ LookAndFeel.installProperty( getComponent(), "echoChar", button.isSelected()
+ ? '\0'
+ : (echoChar != null ? echoChar : '*'));
+ } );
+ return button;
+ }
+
+ /** @since 2 */
+ protected void uninstallRevealButton() {
+ if( revealButton != null ) {
+ getComponent().remove( revealButton );
+ revealButton = null;
+ }
+ }
+
+ @Override
+ protected JComponent[] getTrailingComponents() {
+ return new JComponent[] { trailingComponent, revealButton, clearButton };
+ }
}
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 b6946080..0dca6fc8 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
@@ -35,6 +35,7 @@ import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
@@ -45,10 +46,13 @@ import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.Caret;
+import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
@@ -103,6 +107,10 @@ public class FlatTextFieldUI
/** @since 2 */ @Styleable protected Icon trailingIcon;
/** @since 2 */ protected JComponent leadingComponent;
/** @since 2 */ protected JComponent trailingComponent;
+ /** @since 2 */ protected JComponent clearButton;
+
+ // only used via styling (not in UI defaults, but has likewise client properties)
+ /** @since 2 */ @Styleable protected boolean showClearButton;
private Color oldDisabledBackground;
private Color oldInactiveBackground;
@@ -110,6 +118,7 @@ public class FlatTextFieldUI
private Insets defaultMargin;
private FocusListener focusListener;
+ private DocumentListener documentListener;
private Map oldStyleValues;
private AtomicBoolean borderShared;
@@ -126,6 +135,7 @@ public class FlatTextFieldUI
installLeadingComponent();
installTrailingComponent();
+ installClearButton();
installStyle();
}
@@ -134,6 +144,7 @@ public class FlatTextFieldUI
public void uninstallUI( JComponent c ) {
uninstallLeadingComponent();
uninstallTrailingComponent();
+ uninstallClearButton();
super.uninstallUI( c );
@@ -196,6 +207,11 @@ public class FlatTextFieldUI
getComponent().removeFocusListener( focusListener );
focusListener = null;
+
+ if( documentListener != null ) {
+ getComponent().getDocument().removeDocumentListener( documentListener );
+ documentListener = null;
+ }
}
@Override
@@ -254,9 +270,47 @@ public class FlatTextFieldUI
c.revalidate();
c.repaint();
break;
+
+ case TEXT_FIELD_SHOW_CLEAR_BUTTON:
+ uninstallClearButton();
+ installClearButton();
+ c.revalidate();
+ c.repaint();
+ break;
+
+ case "enabled":
+ case "editable":
+ updateClearButton();
+ break;
+
+ case "document":
+ if( documentListener != null ) {
+ if( e.getOldValue() instanceof Document )
+ ((Document)e.getOldValue()).removeDocumentListener( documentListener );
+ if( e.getNewValue() instanceof Document )
+ ((Document)e.getNewValue()).addDocumentListener( documentListener );
+
+ updateClearButton();
+ }
+ break;
}
}
+ /** @since 2 */
+ protected void installDocumentListener() {
+ if( documentListener != null )
+ return;
+
+ documentListener = new FlatDocumentListener();
+ getComponent().getDocument().addDocumentListener( documentListener );
+ }
+
+ /** @since 2 */
+ protected void documentChanged( DocumentEvent e ) {
+ if( clearButton != null )
+ updateClearButton();
+ }
+
/** @since 2 */
protected void installStyle() {
try {
@@ -275,10 +329,15 @@ public class FlatTextFieldUI
protected void applyStyle( Object style ) {
oldDisabledBackground = disabledBackground;
oldInactiveBackground = inactiveBackground;
+ boolean oldShowClearButton = showClearButton;
oldStyleValues = FlatStylingSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
updateBackground();
+ if( showClearButton != oldShowClearButton ) {
+ uninstallClearButton();
+ installClearButton();
+ }
}
/** @since 2 */
@@ -474,10 +533,14 @@ debug*/
size.width += getLeadingIconWidth() + getTrailingIconWidth();
// add width of leading and trailing components
- if( leadingComponent != null && leadingComponent.isVisible() )
- size.width += leadingComponent.getPreferredSize().width;
- if( trailingComponent != null && trailingComponent.isVisible() )
- size.width += trailingComponent.getPreferredSize().width;
+ for( JComponent comp : getLeadingComponents() ) {
+ if( comp != null && comp.isVisible() )
+ size.width += comp.getPreferredSize().width;
+ }
+ for( JComponent comp : getTrailingComponents() ) {
+ if( comp != null && comp.isVisible() )
+ size.width += comp.getPreferredSize().width;
+ }
return size;
}
@@ -558,17 +621,24 @@ debug*/
boolean ltr = isLeftToRight();
// remove width of leading/trailing components
- JComponent leftComponent = ltr ? leadingComponent : trailingComponent;
- JComponent rightComponent = ltr ? trailingComponent : leadingComponent;
- boolean leftVisible = leftComponent != null && leftComponent.isVisible();
- boolean rightVisible = rightComponent != null && rightComponent.isVisible();
- if( leftVisible ) {
- int w = leftComponent.getPreferredSize().width;
- r.x += w;
- r.width -= w;
+ JComponent[] leftComponents = ltr ? getLeadingComponents() : getTrailingComponents();
+ JComponent[] rightComponents = ltr ? getTrailingComponents() : getLeadingComponents();
+ boolean leftVisible = false;
+ boolean rightVisible = false;
+ for( JComponent leftComponent : leftComponents ) {
+ if( leftComponent != null && leftComponent.isVisible() ) {
+ int w = leftComponent.getPreferredSize().width;
+ r.x += w;
+ r.width -= w;
+ leftVisible = true;
+ }
+ }
+ for( JComponent rightComponent : rightComponents ) {
+ if( rightComponent != null && rightComponent.isVisible() ) {
+ r.width -= rightComponent.getPreferredSize().width;
+ rightVisible = true;
+ }
}
- if( rightVisible )
- r.width -= rightComponent.getPreferredSize().width;
// if a leading/trailing icons (or components) are shown, then the left/right margins are reduced
// to the top margin, which places the icon nicely centered on left/right side
@@ -671,6 +741,87 @@ debug*/
}
}
+ /** @since 2 */
+ protected void installClearButton() {
+ JTextComponent c = getComponent();
+ if( clientPropertyBoolean( c, TEXT_FIELD_SHOW_CLEAR_BUTTON, showClearButton ) ) {
+ clearButton = createClearButton();
+ updateClearButton();
+ installDocumentListener();
+ installLayout();
+ c.add( clearButton );
+ }
+ }
+
+ /** @since 2 */
+ protected void uninstallClearButton() {
+ if( clearButton != null ) {
+ getComponent().remove( clearButton );
+ clearButton = null;
+ }
+ }
+
+ /** @since 2 */
+ protected JComponent createClearButton() {
+ JButton button = new JButton();
+ button.putClientProperty( STYLE_CLASS, "clearButton" );
+ button.putClientProperty( BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON );
+ button.setCursor( Cursor.getDefaultCursor() );
+ button.addActionListener( e -> clearButtonClicked() );
+ return button;
+ }
+
+ /** @since 2 */
+ @SuppressWarnings( "unchecked" )
+ protected void clearButtonClicked() {
+ JTextComponent c = getComponent();
+ Object callback = c.getClientProperty( TEXT_FIELD_CLEAR_CALLBACK );
+ if( callback instanceof Runnable )
+ ((Runnable)callback).run();
+ else if( callback instanceof Consumer )
+ ((Consumer)callback).accept( c );
+ else
+ c.setText( "" );
+ }
+
+ /** @since 2 */
+ protected void updateClearButton() {
+ if( clearButton == null )
+ return;
+
+ JTextComponent c = getComponent();
+ boolean visible = c.isEnabled() && c.isEditable() && c.getDocument().getLength() > 0;
+ if( visible != clearButton.isVisible() ) {
+ clearButton.setVisible( visible );
+ c.revalidate();
+ c.repaint();
+ }
+ }
+
+ /**
+ * Returns components placed at the leading side of the text field.
+ * The returned array may contain {@code null}.
+ * The default implementation returns {@link #leadingComponent}.
+ *
+ * @since 2
+ */
+ protected JComponent[] getLeadingComponents() {
+ return new JComponent[] { leadingComponent };
+ }
+
+ /**
+ * Returns components placed at the trailing side of the text field.
+ * The returned array may contain {@code null}.
+ * The default implementation returns {@link #trailingComponent} and {@link #clearButton}.
+ *
+ * Note: The components in the array must be in reverse (visual) order.
+ *
+ * @since 2
+ */
+ protected JComponent[] getTrailingComponents() {
+ return new JComponent[] { trailingComponent, clearButton };
+ }
+
/** @since 2 */
protected void prepareLeadingOrTrailingComponent( JComponent c ) {
c.putClientProperty( STYLE_CLASS, "inTextField" );
@@ -686,7 +837,8 @@ debug*/
}
}
- private void installLayout() {
+ /** @since 2 */
+ protected void installLayout() {
JTextComponent c = getComponent();
LayoutManager oldLayout = c.getLayout();
if( !(oldLayout instanceof FlatTextFieldLayout) )
@@ -731,25 +883,30 @@ debug*/
if( delegate != null )
delegate.layoutContainer( parent );
- if( leadingComponent == null && trailingComponent == null )
- return;
-
int ow = FlatUIUtils.getBorderFocusAndLineWidth( getComponent() );
int h = parent.getHeight() - ow - ow;
boolean ltr = isLeftToRight();
- JComponent leftComponent = ltr ? leadingComponent : trailingComponent;
- JComponent rightComponent = ltr ? trailingComponent : leadingComponent;
+ JComponent[] leftComponents = ltr ? getLeadingComponents() : getTrailingComponents();
+ JComponent[] rightComponents = ltr ? getTrailingComponents() : getLeadingComponents();
- // layout left component
- if( leftComponent != null && leftComponent.isVisible() ) {
- int w = leftComponent.getPreferredSize().width;
- leftComponent.setBounds( ow, ow, w, h );
+ // layout left components
+ int x = ow;
+ for( JComponent leftComponent : leftComponents ) {
+ if( leftComponent != null && leftComponent.isVisible() ) {
+ int cw = leftComponent.getPreferredSize().width;
+ leftComponent.setBounds( x, ow, cw, h );
+ x += cw;
+ }
}
- // layout right component
- if( rightComponent != null && rightComponent.isVisible() ) {
- int w = rightComponent.getPreferredSize().width;
- rightComponent.setBounds( parent.getWidth() - ow - w, ow, w, h );
+ // layout right components
+ x = parent.getWidth() - ow;
+ for( JComponent rightComponent : rightComponents ) {
+ if( rightComponent != null && rightComponent.isVisible() ) {
+ int cw = rightComponent.getPreferredSize().width;
+ x -= cw;
+ rightComponent.setBounds( x, ow, cw, h );
+ }
}
}
@@ -780,4 +937,24 @@ debug*/
((LayoutManager2)delegate).invalidateLayout( target );
}
}
+ //---- class FlatDocumentListener -----------------------------------------
+
+ private class FlatDocumentListener
+ implements DocumentListener
+ {
+ @Override
+ public void insertUpdate( DocumentEvent e ) {
+ documentChanged( e );
+ }
+
+ @Override
+ public void removeUpdate( DocumentEvent e ) {
+ documentChanged( e );
+ }
+
+ @Override
+ public void changedUpdate( DocumentEvent e ) {
+ documentChanged( e );
+ }
+ }
}
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
index 53879b71..e4d4dbfc 100644
--- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
+++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
@@ -484,7 +484,10 @@ PasswordField.placeholderForeground = @disabledForeground
PasswordField.iconTextGap = 4
PasswordField.echoChar = \u2022
PasswordField.showCapsLock = true
+PasswordField.showRevealButton = false
PasswordField.capsLockIcon = com.formdev.flatlaf.icons.FlatCapsLockIcon
+PasswordField.revealIcon = com.formdev.flatlaf.icons.FlatRevealIcon
+PasswordField.revealIconColor = lazy(Actions.Grey)
#---- Popup ----
@@ -907,3 +910,16 @@ Tree.icon.openColor = @icon
[style]ToolBarSeparator.inTextField = \
separatorWidth: 3
+
+
+#---- clearButton ----
+# for clear/cancel button in text fields
+
+[style]Button.clearButton = \
+ icon: com.formdev.flatlaf.icons.FlatClearIcon; \
+ focusable: false; \
+ toolbar.margin: 1,1,1,1; \
+ toolbar.spacingInsets: 1,1,1,1; \
+ background: $TextField.background; \
+ toolbar.hoverBackground: $TextField.background; \
+ toolbar.pressedBackground: $TextField.background
diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java
index e663fba6..80900989 100644
--- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java
+++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java
@@ -398,7 +398,8 @@ public class TestFlatStyleableInfo
Map> expected = new LinkedHashMap<>();
expectedMap( expected,
- "showCapsLock", boolean.class
+ "showCapsLock", boolean.class,
+ "showRevealButton", boolean.class
);
// FlatPasswordFieldUI extends FlatTextFieldUI
@@ -823,7 +824,8 @@ public class TestFlatStyleableInfo
"focusedBackground", Color.class,
"iconTextGap", int.class,
"leadingIcon", Icon.class,
- "trailingIcon", Icon.class
+ "trailingIcon", Icon.class,
+ "showClearButton", boolean.class
);
// border
diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java
index b63a234d..77654ca9 100644
--- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java
+++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java
@@ -551,6 +551,7 @@ public class TestFlatStyling
textField( ui );
ui.applyStyle( "showCapsLock: true" );
+ ui.applyStyle( "showRevealButton: true" );
// capsLockIcon
ui.applyStyle( "capsLockIconColor: #fff" );
@@ -1011,6 +1012,8 @@ public class TestFlatStyling
ui.applyStyle( "leadingIcon: com.formdev.flatlaf.icons.FlatSearchIcon" );
ui.applyStyle( "trailingIcon: com.formdev.flatlaf.icons.FlatClearIcon" );
+ ui.applyStyle( "showClearButton: true" );
+
// border
flatTextBorder( style -> ui.applyStyle( style ) );
diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.java
index dc9e05e3..6c2e9f23 100644
--- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.java
+++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.java
@@ -38,6 +38,11 @@ class BasicComponentsPanel
BasicComponentsPanel() {
initComponents();
+ // show reveal button for password field
+ // to enable this for all password fields use:
+ // UIManager.put( "PasswordField.showRevealButton", true );
+ passwordField1.putClientProperty( FlatClientProperties.STYLE, "showRevealButton: true" );
+
// search history button
JButton searchHistoryButton = new JButton( new FlatSearchWithHistoryIcon( true ) );
searchHistoryButton.setToolTipText( "Search History" );
@@ -73,6 +78,10 @@ class BasicComponentsPanel
searchToolbar.addSeparator();
searchToolbar.add( regexButton );
compsTextField.putClientProperty( FlatClientProperties.TEXT_FIELD_TRAILING_COMPONENT, searchToolbar );
+
+ // show clear button (if text field is not empty)
+ compsTextField.putClientProperty( FlatClientProperties.TEXT_FIELD_SHOW_CLEAR_BUTTON, true );
+ clearTextField.putClientProperty( FlatClientProperties.TEXT_FIELD_SHOW_CLEAR_BUTTON, true );
}
private void initComponents() {
@@ -124,7 +133,7 @@ class BasicComponentsPanel
JFormattedTextField formattedTextField4 = new JFormattedTextField();
JFormattedTextField formattedTextField5 = new JFormattedTextField();
JLabel passwordFieldLabel = new JLabel();
- JPasswordField passwordField1 = new JPasswordField();
+ passwordField1 = new JPasswordField();
JPasswordField passwordField2 = new JPasswordField();
JPasswordField passwordField3 = new JPasswordField();
JPasswordField passwordField4 = new JPasswordField();
@@ -173,6 +182,7 @@ class BasicComponentsPanel
JTextField iconsTextField = new JTextField();
JLabel compsLabel = new JLabel();
compsTextField = new JTextField();
+ clearTextField = new JTextField();
JLabel fontsLabel = new JLabel();
JLabel h00Label = new JLabel();
JLabel h0Label = new JLabel();
@@ -734,6 +744,10 @@ class BasicComponentsPanel
add(compsLabel, "cell 0 15");
add(compsTextField, "cell 1 15 2 1,growx");
+ //---- clearTextField ----
+ clearTextField.setText("clear me");
+ add(clearTextField, "cell 3 15,growx");
+
//---- fontsLabel ----
fontsLabel.setText("Typography / Fonts:");
add(fontsLabel, "cell 0 16");
@@ -904,6 +918,8 @@ class BasicComponentsPanel
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
+ private JPasswordField passwordField1;
private JTextField compsTextField;
+ private JTextField clearTextField;
// JFormDesigner - End of variables declaration //GEN-END:variables
}
diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.jfd
index c5eb1554..b2735da8 100644
--- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.jfd
+++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/BasicComponentsPanel.jfd
@@ -375,6 +375,9 @@ new FormModel {
add( new FormComponent( "javax.swing.JPasswordField" ) {
name: "passwordField1"
"text": "Editable"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 8,growx"
} )
@@ -685,6 +688,15 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 15 2 1,growx"
} )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "clearTextField"
+ "text": "clear me"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 3 15,growx"
+ } )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "fontsLabel"
"text": "Typography / Fonts:"
diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.java
index 9c79f129..d925d36d 100644
--- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.java
+++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.java
@@ -43,6 +43,7 @@ import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumnModel;
import com.formdev.flatlaf.FlatLaf;
+import com.formdev.flatlaf.extras.components.FlatTextField;
import com.formdev.flatlaf.icons.FlatAbstractIcon;
import com.formdev.flatlaf.ui.FlatBorder;
import com.formdev.flatlaf.ui.FlatEmptyBorder;
@@ -557,7 +558,7 @@ public class FlatUIDefaultsInspector
panel = new JPanel();
filterPanel = new JPanel();
flterLabel = new JLabel();
- filterField = new JTextField();
+ filterField = new FlatTextField();
valueTypeLabel = new JLabel();
valueTypeField = new JComboBox<>();
scrollPane = new JScrollPane();
@@ -588,7 +589,8 @@ public class FlatUIDefaultsInspector
new Insets(0, 0, 0, 10), 0, 0));
//---- filterField ----
- filterField.putClientProperty("JTextField.placeholderText", "enter one or more filter strings, separated by space characters");
+ filterField.setPlaceholderText("enter one or more filter strings, separated by space characters");
+ filterField.setShowClearButton(true);
filterPanel.add(filterField, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 10), 0, 0));
@@ -667,7 +669,7 @@ public class FlatUIDefaultsInspector
private JPanel panel;
private JPanel filterPanel;
private JLabel flterLabel;
- private JTextField filterField;
+ private FlatTextField filterField;
private JLabel valueTypeLabel;
private JComboBox valueTypeField;
private JScrollPane scrollPane;
diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.jfd b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.jfd
index f7baa2f1..d81ca863 100644
--- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.jfd
+++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatUIDefaultsInspector.jfd
@@ -20,9 +20,10 @@ new FormModel {
"labelFor": new FormReference( "filterField" )
"displayedMnemonic": 70
}, new FormLayoutConstraints( class com.jformdesigner.runtime.GridBagConstraintsEx ) )
- add( new FormComponent( "javax.swing.JTextField" ) {
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTextField" ) {
name: "filterField"
- "$client.JTextField.placeholderText": "enter one or more filter strings, separated by space characters"
+ "placeholderText": "enter one or more filter strings, separated by space characters"
+ "showClearButton": true
}, new FormLayoutConstraints( class com.jformdesigner.runtime.GridBagConstraintsEx ) {
"gridx": 1
} )
diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatFormattedTextField.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatFormattedTextField.java
index 326930f7..c3aa8826 100644
--- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatFormattedTextField.java
+++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatFormattedTextField.java
@@ -144,6 +144,26 @@ public class FlatFormattedTextField
}
+ /**
+ * Returns whether a "clear" (or "cancel") button is shown.
+ *
+ * @since 2
+ */
+ public boolean isShowClearButton() {
+ return getClientPropertyBoolean( TEXT_FIELD_SHOW_CLEAR_BUTTON, false );
+ }
+
+ /**
+ * Specifies whether a "clear" (or "cancel") button is shown on the trailing side
+ * if the text field is not empty, editable and enabled.
+ *
+ * @since 2
+ */
+ public void setShowClearButton( boolean showClearButton ) {
+ putClientPropertyBoolean( TEXT_FIELD_SHOW_CLEAR_BUTTON, showClearButton, false );
+ }
+
+
/**
* Returns whether all text is selected when the text component gains focus.
*/
diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatPasswordField.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatPasswordField.java
index cd7f2374..7c36be76 100644
--- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatPasswordField.java
+++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatPasswordField.java
@@ -144,6 +144,26 @@ public class FlatPasswordField
}
+ /**
+ * Returns whether a "clear" (or "cancel") button is shown.
+ *
+ * @since 2
+ */
+ public boolean isShowClearButton() {
+ return getClientPropertyBoolean( TEXT_FIELD_SHOW_CLEAR_BUTTON, false );
+ }
+
+ /**
+ * Specifies whether a "clear" (or "cancel") button is shown on the trailing side
+ * if the text field is not empty, editable and enabled.
+ *
+ * @since 2
+ */
+ public void setShowClearButton( boolean showClearButton ) {
+ putClientPropertyBoolean( TEXT_FIELD_SHOW_CLEAR_BUTTON, showClearButton, false );
+ }
+
+
/**
* Returns whether all text is selected when the text component gains focus.
*/
diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatTextField.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatTextField.java
index c7747bf5..c2d14a07 100644
--- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatTextField.java
+++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/components/FlatTextField.java
@@ -143,6 +143,26 @@ public class FlatTextField
}
+ /**
+ * Returns whether a "clear" (or "cancel") button is shown.
+ *
+ * @since 2
+ */
+ public boolean isShowClearButton() {
+ return getClientPropertyBoolean( TEXT_FIELD_SHOW_CLEAR_BUTTON, false );
+ }
+
+ /**
+ * Specifies whether a "clear" (or "cancel") button is shown on the trailing side
+ * if the text field is not empty, editable and enabled.
+ *
+ * @since 2
+ */
+ public void setShowClearButton( boolean showClearButton ) {
+ putClientPropertyBoolean( TEXT_FIELD_SHOW_CLEAR_BUTTON, showClearButton, false );
+ }
+
+
// NOTE: enum names must be equal to allowed strings
public enum SelectAllOnFocusPolicy { never, once, always };
diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt
index 7cf0ed6a..a3040e7a 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt
@@ -711,9 +711,12 @@ PasswordField.inactiveBackground #3c3f41 HSL 204 4 25 javax.swing.plaf.Co
PasswordField.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
PasswordField.placeholderForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
+PasswordField.revealIcon [lazy] 16,16 com.formdev.flatlaf.icons.FlatRevealIcon [UI]
+PasswordField.revealIconColor [lazy] #afb1b3 HSL 210 3 69 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionBackground #4b6eaf HSL 219 40 49 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
PasswordField.showCapsLock true
+PasswordField.showRevealButton false
PasswordFieldUI com.formdev.flatlaf.ui.FlatPasswordFieldUI
@@ -1421,6 +1424,7 @@ ViewportUI com.formdev.flatlaf.ui.FlatViewportUI
#---- [style]Button ----
+[style]Button.clearButton icon: com.formdev.flatlaf.icons.FlatClearIcon; focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; background: $TextField.background; toolbar.hoverBackground: $TextField.background; toolbar.pressedBackground: $TextField.background
[style]Button.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; background: $TextField.background; toolbar.hoverBackground: lighten($TextField.background,4%,derived); toolbar.pressedBackground: lighten($TextField.background,6%,derived); toolbar.selectedBackground: lighten($TextField.background,12%,derived)
diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt
index c0ae8ece..fc4ffa67 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt
@@ -716,9 +716,12 @@ PasswordField.inactiveBackground #f2f2f2 HSL 0 0 95 javax.swing.plaf.Co
PasswordField.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
PasswordField.placeholderForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
+PasswordField.revealIcon [lazy] 16,16 com.formdev.flatlaf.icons.FlatRevealIcon [UI]
+PasswordField.revealIconColor [lazy] #6e6e6e HSL 0 0 43 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionBackground #2675bf HSL 209 67 45 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
PasswordField.showCapsLock true
+PasswordField.showRevealButton false
PasswordFieldUI com.formdev.flatlaf.ui.FlatPasswordFieldUI
@@ -1426,6 +1429,7 @@ ViewportUI com.formdev.flatlaf.ui.FlatViewportUI
#---- [style]Button ----
+[style]Button.clearButton icon: com.formdev.flatlaf.icons.FlatClearIcon; focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; background: $TextField.background; toolbar.hoverBackground: $TextField.background; toolbar.pressedBackground: $TextField.background
[style]Button.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; background: $TextField.background; toolbar.hoverBackground: darken($TextField.background,4%,derived); toolbar.pressedBackground: darken($TextField.background,8%,derived); toolbar.selectedBackground: darken($TextField.background,12%,derived)
diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt
index be298499..7dcba7ad 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt
@@ -726,9 +726,12 @@ PasswordField.inactiveBackground #f0f0f0 HSL 0 0 94 javax.swing.plaf.Co
PasswordField.inactiveForeground #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
PasswordField.placeholderForeground #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
+PasswordField.revealIcon [lazy] 16,16 com.formdev.flatlaf.icons.FlatRevealIcon [UI]
+PasswordField.revealIconColor [lazy] #6e6e6e HSL 0 0 43 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionBackground #00aa00 HSL 120 100 33 javax.swing.plaf.ColorUIResource [UI]
PasswordField.selectionForeground #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
PasswordField.showCapsLock true
+PasswordField.showRevealButton false
PasswordFieldUI com.formdev.flatlaf.ui.FlatPasswordFieldUI
@@ -1439,6 +1442,7 @@ ViewportUI com.formdev.flatlaf.ui.FlatViewportUI
#---- [style]Button ----
+[style]Button.clearButton icon: com.formdev.flatlaf.icons.FlatClearIcon; focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1; background: $TextField.background; toolbar.hoverBackground: $TextField.background; toolbar.pressedBackground: $TextField.background
[style]Button.inTextField focusable: false; toolbar.margin: 1,1,1,1; toolbar.spacingInsets: 1,1,1,1
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java
index a0c66148..0a3a2ad2 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java
@@ -121,6 +121,19 @@ public class FlatTextComponentsTest
}
}
+ private void showClearButton() {
+ putTextFieldClientProperty( FlatClientProperties.TEXT_FIELD_SHOW_CLEAR_BUTTON,
+ showClearButtonCheckBox.isSelected() );
+ }
+
+ private void showRevealButton() {
+ for( Component c : getComponents() ) {
+ if( c instanceof JPasswordField )
+ ((JPasswordField)c).putClientProperty(FlatClientProperties.STYLE,
+ showRevealButtonCheckBox.isSelected() ? "showRevealButton: true" : null );
+ }
+ }
+
private void putTextFieldClientProperty( String key, Object value ) {
for( Component c : getComponents() ) {
if( c instanceof JTextField )
@@ -168,6 +181,8 @@ public class FlatTextComponentsTest
trailingComponentCheckBox = new JCheckBox();
leadingComponentVisibleCheckBox = new JCheckBox();
trailingComponentVisibleCheckBox = new JCheckBox();
+ showClearButtonCheckBox = new JCheckBox();
+ showRevealButtonCheckBox = new JCheckBox();
JLabel passwordFieldLabel = new JLabel();
JPasswordField passwordField1 = new JPasswordField();
JPasswordField passwordField3 = new JPasswordField();
@@ -319,6 +334,8 @@ public class FlatTextComponentsTest
"[]0" +
"[]" +
"[]0" +
+ "[]" +
+ "[]" +
"[]"));
//---- button1 ----
@@ -404,6 +421,18 @@ public class FlatTextComponentsTest
trailingComponentVisibleCheckBox.setName("trailingComponentVisibleCheckBox");
trailingComponentVisibleCheckBox.addActionListener(e -> trailingComponentVisible());
panel1.add(trailingComponentVisibleCheckBox, "cell 0 10 2 1,alignx left,growx 0");
+
+ //---- showClearButtonCheckBox ----
+ showClearButtonCheckBox.setText("clear button");
+ showClearButtonCheckBox.setName("showClearButtonCheckBox");
+ showClearButtonCheckBox.addActionListener(e -> showClearButton());
+ panel1.add(showClearButtonCheckBox, "cell 0 11 2 1,alignx left,growx 0");
+
+ //---- showRevealButtonCheckBox ----
+ showRevealButtonCheckBox.setText("password reveal button");
+ showRevealButtonCheckBox.setName("showRevealButtonCheckBox");
+ showRevealButtonCheckBox.addActionListener(e -> showRevealButton());
+ panel1.add(showRevealButtonCheckBox, "cell 0 12 2 1,alignx left,growx 0");
}
add(panel1, "cell 4 0 1 10,aligny top,growy 0");
@@ -719,6 +748,8 @@ public class FlatTextComponentsTest
private JCheckBox trailingComponentCheckBox;
private JCheckBox leadingComponentVisibleCheckBox;
private JCheckBox trailingComponentVisibleCheckBox;
+ private JCheckBox showClearButtonCheckBox;
+ private JCheckBox showRevealButtonCheckBox;
private JTextField textField;
private JCheckBox dragEnabledCheckBox;
private JTextArea textArea;
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd
index 2dfcfb7b..0d8d6b31 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd
@@ -77,7 +77,7 @@ new FormModel {
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3"
"$columnConstraints": "[fill][fill]"
- "$rowConstraints": "[][][][][][]0[][]0[][]0[]"
+ "$rowConstraints": "[][][][][][]0[][]0[][]0[][][]"
} ) {
name: "panel1"
"border": new javax.swing.border.TitledBorder( "Control" )
@@ -210,6 +210,26 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 10 2 1,alignx left,growx 0"
} )
+ add( new FormComponent( "javax.swing.JCheckBox" ) {
+ name: "showClearButtonCheckBox"
+ "text": "clear button"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showClearButton", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 11 2 1,alignx left,growx 0"
+ } )
+ add( new FormComponent( "javax.swing.JCheckBox" ) {
+ name: "showRevealButtonCheckBox"
+ "text": "password reveal button"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showRevealButton", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 12 2 1,alignx left,growx 0"
+ } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 0 1 10,aligny top,growy 0"
} )
diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.java
index 3c907a2d..820be31e 100644
--- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.java
+++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.java
@@ -304,6 +304,7 @@ class FlatFindReplaceBar
//---- findField ----
findField.setColumns(16);
findField.setSelectAllOnFocusPolicy(FlatTextField.SelectAllOnFocusPolicy.always);
+ findField.setShowClearButton(true);
findField.addActionListener(e -> find());
add(findField, "cell 1 0");
@@ -365,6 +366,7 @@ class FlatFindReplaceBar
//---- replaceField ----
replaceField.setColumns(16);
replaceField.setSelectAllOnFocusPolicy(FlatTextField.SelectAllOnFocusPolicy.always);
+ replaceField.setShowClearButton(true);
add(replaceField, "cell 1 1");
//======== toolBar1 ========
diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.jfd b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.jfd
index e852b805..4f1c399b 100644
--- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.jfd
+++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.jfd
@@ -22,6 +22,7 @@ new FormModel {
name: "findField"
"columns": 16
"selectAllOnFocusPolicy": enum com.formdev.flatlaf.extras.components.FlatTextField$SelectAllOnFocusPolicy always
+ "showClearButton": true
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "find", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
@@ -91,6 +92,7 @@ new FormModel {
name: "replaceField"
"columns": 16
"selectAllOnFocusPolicy": enum com.formdev.flatlaf.extras.components.FlatTextField$SelectAllOnFocusPolicy always
+ "showClearButton": true
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1"
} )
diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt
index 3257247b..e719971f 100644
--- a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt
+++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt
@@ -557,9 +557,12 @@ PasswordField.inactiveBackground
PasswordField.inactiveForeground
PasswordField.margin
PasswordField.placeholderForeground
+PasswordField.revealIcon
+PasswordField.revealIconColor
PasswordField.selectionBackground
PasswordField.selectionForeground
PasswordField.showCapsLock
+PasswordField.showRevealButton
PasswordFieldUI
Popup.dropShadowColor
Popup.dropShadowInsets
@@ -1115,6 +1118,7 @@ ViewportUI
[style].monospaced
[style].semibold
[style].small
+[style]Button.clearButton
[style]Button.inTextField
[style]ToggleButton.inTextField
[style]ToolBar.inTextField