diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc7efe32..052d0ca3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@ FlatLaf Change Log
#### New features and improvements
+- TextField, FormattedTextField and PasswordField: Support leading and trailing
+ icons (set client property `JTextField.leadingIcon` or
+ `JTextField.trailingIcon` to an `Icon`). (issue #368)
- InternalFrame: Double-click on icon in internal frame title bar now closes the
internal frame. (issue #374)
- IntelliJ Themes: Removed deprecated `install()` methods.
@@ -55,8 +58,8 @@ FlatLaf Change Log
#### New features and improvements
-- TextField, FormattedTextField and PasswordField: Support adding extra padding.
- (set client property `JTextField.padding` to `Insets`).
+- TextField, FormattedTextField and PasswordField: Support adding extra padding
+ (set client property `JTextField.padding` to an `Insets`).
- PasswordField: UI delegate `FlatPasswordFieldUI` now extends `FlatTextFieldUI`
(instead of `BasicPasswordFieldUI`) to avoid duplicate code and for easier
extensibility.
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 dace152f..780cb166 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java
@@ -745,6 +745,26 @@ public interface FlatClientProperties
*/
String TEXT_FIELD_PADDING = "JTextField.padding";
+ /**
+ * Specifies an icon that will be placed at the leading edge of the text field.
+ *
+ * Component {@link javax.swing.JTextField} (and subclasses)
+ * Value type {@link javax.swing.Icon}
+ *
+ * @since 2
+ */
+ String TEXT_FIELD_LEADING_ICON = "JTextField.leadingIcon";
+
+ /**
+ * Specifies an icon that will be placed at the trailing edge of the text field.
+ *
+ * Component {@link javax.swing.JTextField} (and subclasses)
+ * Value type {@link javax.swing.Icon}
+ *
+ * @since 2
+ */
+ String TEXT_FIELD_TRAILING_ICON = "JTextField.trailingIcon";
+
//---- JToggleButton ------------------------------------------------------
/**
@@ -813,8 +833,7 @@ public interface FlatClientProperties
* If the client property is not set, or not a {@link Boolean}, defaultValue is returned.
*/
static Boolean clientPropertyBooleanStrict( JComponent c, String key, Boolean defaultValue ) {
- Object value = c.getClientProperty( key );
- return (value instanceof Boolean) ? (Boolean) value : defaultValue;
+ return clientProperty( c, key, defaultValue, Boolean.class );
}
/**
@@ -831,7 +850,18 @@ public interface FlatClientProperties
* If the client property is not set, or not a color, defaultValue is returned.
*/
static Color clientPropertyColor( JComponent c, String key, Color defaultValue ) {
+ return clientProperty( c, key, defaultValue, Color.class );
+ }
+
+ /**
+ * Returns the value of the specified client property if it is an instance of
+ * the specified type. Otherwise, defaultValue is returned.
+ *
+ * @since 2
+ */
+ @SuppressWarnings( "unchecked" )
+ static T clientProperty( JComponent c, String key, T defaultValue, Class type ) {
Object value = c.getClientProperty( key );
- return (value instanceof Color) ? (Color) value : defaultValue;
+ return type.isInstance( value ) ? (T) value : defaultValue;
}
}
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java
index 83a5aac3..7b20ec61 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java
@@ -18,7 +18,6 @@ package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.EventQueue;
-import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
@@ -68,11 +67,12 @@ public class FlatCaret
protected void adjustVisibility( Rectangle nloc ) {
JTextComponent c = getComponent();
if( c != null && c.getUI() instanceof FlatTextFieldUI ) {
- Insets padding = ((FlatTextFieldUI)c.getUI()).getPadding();
- if( padding != null ) {
- nloc.x -= padding.left;
- nloc.y -= padding.top;
- }
+ // need to fix x location because JTextField.scrollRectToVisible() uses insets.left
+ // (as BasicTextUI.getVisibleEditorRect() does),
+ // but FlatTextFieldUI.getVisibleEditorRect() may add some padding
+ Rectangle r = ((FlatTextFieldUI)c.getUI()).getVisibleEditorRect();
+ if( r != null )
+ nloc.x -= r.x - c.getInsets().left;
}
super.adjustVisibility( nloc );
}
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 a016d7da..6e34a643 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
@@ -43,6 +43,7 @@ import javax.swing.plaf.ComponentUI;
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault FormattedTextField.placeholderForeground Color
* @uiDefault FormattedTextField.focusedBackground Color optional
+ * @uiDefault FormattedTextField.iconTextGap int optional, default is 4
* @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 e1f74421..454e9593 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
@@ -17,8 +17,7 @@
package com.formdev.flatlaf.ui;
import java.awt.Graphics;
-import java.awt.Insets;
-import java.awt.Shape;
+import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
@@ -36,6 +35,7 @@ import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.PasswordView;
import javax.swing.text.View;
+import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}.
@@ -61,6 +61,7 @@ import javax.swing.text.View;
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault PasswordField.placeholderForeground Color
* @uiDefault PasswordField.focusedBackground Color optional
+ * @uiDefault PasswordField.iconTextGap int optional, default is 4
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
* @uiDefault TextComponent.selectAllOnMouseClick boolean
*
@@ -160,29 +161,38 @@ public class FlatPasswordFieldUI
return new PasswordView( elem );
}
+ /** @since 2 */
@Override
- protected void paintSafely( Graphics g ) {
- // safe and restore clipping area because super.paintSafely() modifies it
- // and the caps lock icon would be truncated
- Shape oldClip = g.getClip();
- super.paintSafely( g );
- g.setClip( oldClip );
+ protected void paintIcons( Graphics g, Rectangle r ) {
+ super.paintIcons( g, r );
- paintCapsLock( g );
+ if( isCapsLockVisible() )
+ paintCapsLock( g, r );
}
- protected void paintCapsLock( Graphics g ) {
- if( !isCapsLockVisible() )
- return;
-
+ /** @since 2 */
+ protected void paintCapsLock( Graphics g, Rectangle r ) {
JTextComponent c = getComponent();
- int y = (c.getHeight() - capsLockIcon.getIconHeight()) / 2;
int x = c.getComponentOrientation().isLeftToRight()
- ? c.getWidth() - capsLockIcon.getIconWidth() - y
- : y;
+ ? r.x + r.width - capsLockIcon.getIconWidth()
+ : r.x;
+ int y = r.y + Math.round( (r.height - capsLockIcon.getIconHeight()) / 2f );
capsLockIcon.paintIcon( c, g, x, y );
}
+ /** @since 2 */
+ @Override
+ protected boolean hasTrailingIcon() {
+ return super.hasTrailingIcon() || isCapsLockVisible();
+ }
+
+ /** @since 2 */
+ @Override
+ protected int getTrailingIconWidth() {
+ return super.getTrailingIconWidth()
+ + (isCapsLockVisible() ? capsLockIcon.getIconWidth() + UIScale.scale( iconTextGap ) : 0);
+ }
+
/**
* @since 1.4
*/
@@ -194,18 +204,4 @@ public class FlatPasswordFieldUI
return FlatUIUtils.isPermanentFocusOwner( c ) &&
Toolkit.getDefaultToolkit().getLockingKeyState( KeyEvent.VK_CAPS_LOCK );
}
-
- /**
- * @since 1.4
- */
- @Override
- protected Insets getPadding() {
- Insets padding = super.getPadding();
- if( !isCapsLockVisible() )
- return padding;
-
- boolean ltr = getComponent().getComponentOrientation().isLeftToRight();
- int iconWidth = capsLockIcon.getIconWidth();
- return FlatUIUtils.addInsets( padding, new Insets( 0, ltr ? 0 : iconWidth, 0, ltr ? iconWidth : 0 ) );
- }
}
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 5a02d059..6cd7f88e 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
@@ -16,6 +16,7 @@
package com.formdev.flatlaf.ui;
+import static com.formdev.flatlaf.FlatClientProperties.*;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Container;
@@ -28,6 +29,7 @@ import java.awt.Rectangle;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.util.Objects;
+import javax.swing.Icon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JSpinner;
@@ -39,10 +41,8 @@ import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.Caret;
import javax.swing.text.JTextComponent;
-import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.JavaCompatibility;
-import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF UI delegate for {@link javax.swing.JTextField}.
@@ -68,6 +68,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault Component.isIntelliJTheme boolean
* @uiDefault TextField.placeholderForeground Color
* @uiDefault TextField.focusedBackground Color optional
+ * @uiDefault TextField.iconTextGap int optional, default is 4
* @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always
* @uiDefault TextComponent.selectAllOnMouseClick boolean
*
@@ -80,6 +81,10 @@ public class FlatTextFieldUI
protected boolean isIntelliJTheme;
protected Color placeholderForeground;
protected Color focusedBackground;
+ protected int iconTextGap;
+
+ protected Icon leadingIcon;
+ protected Icon trailingIcon;
private Insets defaultMargin;
@@ -89,6 +94,22 @@ public class FlatTextFieldUI
return new FlatTextFieldUI();
}
+ @Override
+ public void installUI( JComponent c ) {
+ super.installUI( c );
+
+ leadingIcon = clientProperty( c, TEXT_FIELD_LEADING_ICON, null, Icon.class );
+ trailingIcon = clientProperty( c, TEXT_FIELD_TRAILING_ICON, null, Icon.class );
+ }
+
+ @Override
+ public void uninstallUI( JComponent c ) {
+ super.uninstallUI( c );
+
+ leadingIcon = null;
+ trailingIcon = null;
+ }
+
@Override
protected void installDefaults() {
super.installDefaults();
@@ -98,6 +119,7 @@ public class FlatTextFieldUI
isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" );
placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" );
focusedBackground = UIManager.getColor( prefix + ".focusedBackground" );
+ iconTextGap = FlatUIUtils.getUIInt( prefix + ".iconTextGap", 4 );
defaultMargin = UIManager.getInsets( prefix + ".margin" );
@@ -142,20 +164,28 @@ public class FlatTextFieldUI
@Override
protected void propertyChange( PropertyChangeEvent e ) {
super.propertyChange( e );
- propertyChange( getComponent(), e );
- }
- static void propertyChange( JTextComponent c, PropertyChangeEvent e ) {
+ JTextComponent c = getComponent();
switch( e.getPropertyName() ) {
- case FlatClientProperties.PLACEHOLDER_TEXT:
- case FlatClientProperties.COMPONENT_ROUND_RECT:
- case FlatClientProperties.TEXT_FIELD_PADDING:
+ case PLACEHOLDER_TEXT:
+ case COMPONENT_ROUND_RECT:
+ case TEXT_FIELD_PADDING:
c.repaint();
break;
- case FlatClientProperties.MINIMUM_WIDTH:
+ case MINIMUM_WIDTH:
c.revalidate();
break;
+
+ case TEXT_FIELD_LEADING_ICON:
+ leadingIcon = (e.getNewValue() instanceof Icon) ? (Icon) e.getNewValue() : null;
+ c.repaint();
+ break;
+
+ case TEXT_FIELD_TRAILING_ICON:
+ trailingIcon = (e.getNewValue() instanceof Icon) ? (Icon) e.getNewValue() : null;
+ c.repaint();
+ break;
}
}
@@ -164,6 +194,15 @@ public class FlatTextFieldUI
paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground );
paintPlaceholder( g );
+ if( hasLeadingIcon() || hasTrailingIcon() )
+ paintIcons( g, new Rectangle( getIconsRect() ) );
+
+/*debug
+ Rectangle r = getVisibleEditorRect();
+ g.setColor( Color.red );
+ g.drawRect( r.x, r.y, r.width - 1, r.height - 1 );
+debug*/
+
super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) );
}
@@ -230,15 +269,15 @@ public class FlatTextFieldUI
JComponent jc = (parent instanceof JComboBox) ? (JComboBox>) parent : c;
// get placeholder text
- Object placeholder = jc.getClientProperty( FlatClientProperties.PLACEHOLDER_TEXT );
- if( !(placeholder instanceof String) )
+ String placeholder = clientProperty( jc, PLACEHOLDER_TEXT, null, String.class );
+ if( placeholder == null )
return;
// compute placeholder location
Rectangle r = getVisibleEditorRect();
FontMetrics fm = c.getFontMetrics( c.getFont() );
- String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, (String) placeholder, r.width );
- int x = r.x + (c.getComponentOrientation().isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
+ String clippedPlaceholder = JavaCompatibility.getClippedString( c, fm, placeholder, r.width );
+ int x = r.x + (isLeftToRight() ? 0 : r.width - fm.stringWidth( clippedPlaceholder ));
int y = r.y + fm.getAscent() + ((r.height - fm.getHeight()) / 2);
// paint placeholder
@@ -246,6 +285,42 @@ public class FlatTextFieldUI
FlatUIUtils.drawString( c, g, clippedPlaceholder, x, y );
}
+ /**
+ * Paints the leading and trailing icons in the given rectangle.
+ * The rectangle is updated by this method so that subclasses can use it
+ * without painting over leading or trailing icons.
+ *
+ * @since 2
+ */
+ protected void paintIcons( Graphics g, Rectangle r ) {
+ boolean ltr = isLeftToRight();
+ Icon leftIcon = ltr ? leadingIcon : trailingIcon;
+ Icon rightIcon = ltr ? trailingIcon : leadingIcon;
+
+ // paint left icon
+ if( leftIcon != null ) {
+ int x = r.x;
+ int y = r.y + Math.round( (r.height - leftIcon.getIconHeight()) / 2f );
+ leftIcon.paintIcon( getComponent(), g, x, y );
+
+ // update rectangle so that subclasses can use it
+ int w = leftIcon.getIconWidth() + scale( iconTextGap );
+ r.x += w;
+ r.width -= w;
+ }
+
+ // paint right icon
+ if( rightIcon != null ) {
+ int iconWidth = rightIcon.getIconWidth();
+ int x = r.x + r.width - iconWidth;
+ int y = r.y + Math.round( (r.height - rightIcon.getIconHeight()) / 2f );
+ rightIcon.paintIcon( getComponent(), g, x, y );
+
+ // update rectangle so that subclasses can use it
+ r.width -= iconWidth + scale( iconTextGap );
+ }
+ }
+
@Override
public Dimension getPreferredSize( JComponent c ) {
return applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth );
@@ -283,27 +358,104 @@ public class FlatTextFieldUI
return margin instanceof UIResource && Objects.equals( margin, defaultMargin );
}
+ /**
+ * Returns the rectangle used for the root view of the text.
+ * This method is used to place the text.
+ */
@Override
protected Rectangle getVisibleEditorRect() {
+ Rectangle r = getIconsRect();
+ if( r == null )
+ return null;
+
+ // remove space needed for leading and trailing icons
+ int leading = getLeadingIconWidth();
+ int trailing = getTrailingIconWidth();
+ if( leading != 0 || trailing != 0 ) {
+ boolean ltr = isLeftToRight();
+ int left = ltr ? leading : trailing;
+ int right = ltr ? trailing : leading;
+ r.x += left;
+ r.width -= left + right;
+ }
+
+ // remove padding
+ Insets padding = getPadding();
+ if( padding != null )
+ r = FlatUIUtils.subtractInsets( r, padding );
+
+ // make sure that width and height are not negative
+ r.width = Math.max( r.width, 0 );
+ r.height = Math.max( r.height, 0 );
+
+ return r;
+ }
+
+ /**
+ * Returns the rectangle used to paint leading and trailing icons.
+ * It invokes {@code super.getVisibleEditorRect()} and reduces left and/or
+ * right margin if the text field has leading or trailing icons.
+ *
+ * @since 2
+ */
+ protected Rectangle getIconsRect() {
Rectangle r = super.getVisibleEditorRect();
- if( r != null ) {
- // remove padding
- Insets padding = getPadding();
- if( padding != null ) {
- r = FlatUIUtils.subtractInsets( r, padding );
- r.width = Math.max( r.width, 0 );
- r.height = Math.max( r.height, 0 );
+ if( r == null )
+ return null;
+
+ // if a leading/trailing icon is shown, then the left/right margin is reduced
+ // to the top margin, which places the icon nicely centered on left/right side
+ boolean ltr = isLeftToRight();
+ if( ltr ? hasLeadingIcon() : hasTrailingIcon() ) {
+ // reduce left margin
+ Insets margin = getComponent().getMargin();
+ int newLeftMargin = Math.min( margin.left, margin.top );
+ if( newLeftMargin < margin.left ) {
+ int diff = scale( margin.left - newLeftMargin );
+ r.x -= diff;
+ r.width += diff;
}
}
+ if( ltr ? hasTrailingIcon() : hasLeadingIcon() ) {
+ // reduce right margin
+ Insets margin = getComponent().getMargin();
+ int newRightMargin = Math.min( margin.right, margin.top );
+ if( newRightMargin < margin.left )
+ r.width += scale( margin.right - newRightMargin );
+ }
+
return r;
}
+ /** @since 2 */
+ protected boolean hasLeadingIcon() {
+ return leadingIcon != null;
+ }
+
+ /** @since 2 */
+ protected boolean hasTrailingIcon() {
+ return trailingIcon != null;
+ }
+
+ /** @since 2 */
+ protected int getLeadingIconWidth() {
+ return (leadingIcon != null) ? leadingIcon.getIconWidth() + scale( iconTextGap ) : 0;
+ }
+
+ /** @since 2 */
+ protected int getTrailingIconWidth() {
+ return (trailingIcon != null) ? trailingIcon.getIconWidth() + scale( iconTextGap ) : 0;
+ }
+
+ boolean isLeftToRight() {
+ return getComponent().getComponentOrientation().isLeftToRight();
+ }
+
/**
* @since 1.4
*/
protected Insets getPadding() {
- Object padding = getComponent().getClientProperty( FlatClientProperties.TEXT_FIELD_PADDING );
- return (padding instanceof Insets) ? UIScale.scale( (Insets) padding ) : null;
+ return scale( clientProperty( getComponent(), TEXT_FIELD_PADDING, null, Insets.class ) );
}
/**
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 5688074e..dbf56770 100644
--- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
+++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
@@ -273,6 +273,7 @@ FormattedTextField.border = com.formdev.flatlaf.ui.FlatTextBorder
FormattedTextField.margin = @textComponentMargin
FormattedTextField.background = @textComponentBackground
FormattedTextField.placeholderForeground = @disabledText
+FormattedTextField.iconTextGap = 4
#---- HelpButton ----
@@ -413,6 +414,7 @@ PasswordField.border = com.formdev.flatlaf.ui.FlatTextBorder
PasswordField.margin = @textComponentMargin
PasswordField.background = @textComponentBackground
PasswordField.placeholderForeground = @disabledText
+PasswordField.iconTextGap = 4
PasswordField.echoChar = \u2022
PasswordField.showCapsLock = true
PasswordField.capsLockIcon = com.formdev.flatlaf.icons.FlatCapsLockIcon
@@ -680,6 +682,7 @@ TextField.border = com.formdev.flatlaf.ui.FlatTextBorder
TextField.margin = @textComponentMargin
TextField.background = @textComponentBackground
TextField.placeholderForeground = @disabledText
+TextField.iconTextGap = 4
#---- TextPane ----
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 b545ba2e..2d9c57d2 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
@@ -19,6 +19,9 @@ package com.formdev.flatlaf.demo;
import java.awt.Component;
import javax.swing.*;
import javax.swing.text.DefaultEditorKit;
+import com.formdev.flatlaf.FlatClientProperties;
+import com.formdev.flatlaf.extras.FlatSVGIcon;
+import com.formdev.flatlaf.icons.FlatSearchIcon;
import net.miginfocom.swing.*;
/**
@@ -123,6 +126,10 @@ class BasicComponentsPanel
JTextField warningHintsTextField = new JTextField();
JComboBox warningHintsComboBox = new JComboBox<>();
JSpinner warningHintsSpinner = new JSpinner();
+ JLabel iconsLabel = new JLabel();
+ JTextField leadingIconTextField = new JTextField();
+ JTextField trailingIconTextField = new JTextField();
+ JTextField iconsTextField = new JTextField();
JPopupMenu popupMenu1 = new JPopupMenu();
JMenuItem cutMenuItem = new JMenuItem();
JMenuItem copyMenuItem = new JMenuItem();
@@ -132,7 +139,7 @@ class BasicComponentsPanel
setLayout(new MigLayout(
"insets dialog,hidemode 3",
// columns
- "[sizegroup 1]" +
+ "[]" +
"[sizegroup 1]" +
"[sizegroup 1]" +
"[sizegroup 1]" +
@@ -152,6 +159,7 @@ class BasicComponentsPanel
"[]" +
"[]para" +
"[]" +
+ "[]" +
"[]"));
//---- labelLabel ----
@@ -646,6 +654,19 @@ class BasicComponentsPanel
warningHintsSpinner.putClientProperty("JComponent.outline", "warning");
add(warningHintsSpinner, "cell 3 13,growx");
+ //---- iconsLabel ----
+ iconsLabel.setText("Leading/trailing icons:");
+ add(iconsLabel, "cell 0 14");
+ add(leadingIconTextField, "cell 1 14,growx");
+
+ //---- trailingIconTextField ----
+ trailingIconTextField.setText("text");
+ add(trailingIconTextField, "cell 2 14,growx");
+
+ //---- iconsTextField ----
+ iconsTextField.setText("text");
+ add(iconsTextField, "cell 3 14,growx");
+
//======== popupMenu1 ========
{
@@ -670,8 +691,20 @@ class BasicComponentsPanel
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
+ // add leading/trailing icons to text fields
+ leadingIconTextField.putClientProperty( FlatClientProperties.PLACEHOLDER_TEXT, "Search" );
+ leadingIconTextField.putClientProperty( FlatClientProperties.TEXT_FIELD_LEADING_ICON,
+ new FlatSearchIcon() );
+ trailingIconTextField.putClientProperty( FlatClientProperties.TEXT_FIELD_TRAILING_ICON,
+ new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/DataTables.svg" ) );
+ iconsTextField.putClientProperty( FlatClientProperties.TEXT_FIELD_LEADING_ICON,
+ new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/user.svg" ) );
+ iconsTextField.putClientProperty( FlatClientProperties.TEXT_FIELD_TRAILING_ICON,
+ new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/bookmarkGroup.svg" ) );
+
if( FlatLafDemo.screenshotsMode ) {
- Component[] components = {
+ // hide some components
+ Component[] hiddenComponents = {
button13, button14, button15, button16, comboBox5, comboBox6,
textField6, passwordField5,
@@ -683,18 +716,26 @@ class BasicComponentsPanel
errorHintsLabel, errorHintsTextField, errorHintsComboBox, errorHintsSpinner,
warningHintsLabel, warningHintsTextField, warningHintsComboBox, warningHintsSpinner,
};
-
- for( Component c : components )
+ for( Component c : hiddenComponents )
c.setVisible( false );
- // move password fields one row up
+ // move leading/trailing icon fields and password fields some rows up
Component[] formattedTextFields = { formattedTextFieldLabel, formattedTextField1, formattedTextField2, formattedTextField3, formattedTextField4 };
Component[] passwordFields = { passwordFieldLabel, passwordField1, passwordField2, passwordField3, passwordField4 };
+ Component[] iconsFields = { iconsLabel, leadingIconTextField, trailingIconTextField, iconsTextField };
MigLayout layout = (MigLayout) getLayout();
+ for( int i = 0; i < iconsFields.length; i++ ) {
+ Object cons = layout.getComponentConstraints( passwordFields[i] );
+ layout.setComponentConstraints( iconsFields[i], cons );
+ }
for( int i = 0; i < passwordFields.length; i++ ) {
Object cons = layout.getComponentConstraints( formattedTextFields[i] );
layout.setComponentConstraints( passwordFields[i], cons );
}
+
+ // make "Not editable disabled" combobox smaller
+ Object cons = layout.getComponentConstraints( comboBox4 );
+ layout.setComponentConstraints( comboBox4, cons + ",width 50:50" );
}
}
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 75ed432e..53d6e8aa 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
@@ -1,4 +1,4 @@
-JFDML JFormDesigner: "7.0.2.0.298" Java: "14" encoding: "UTF-8"
+JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -8,8 +8,8 @@ new FormModel {
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "insets dialog,hidemode 3"
- "$columnConstraints": "[sizegroup 1][sizegroup 1][sizegroup 1][sizegroup 1][][]"
- "$rowConstraints": "[][][][][][][][][][][][]para[][]"
+ "$columnConstraints": "[][sizegroup 1][sizegroup 1][sizegroup 1][][]"
+ "$rowConstraints": "[][][][][][][][][][][][]para[][][]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
@@ -648,9 +648,32 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 13,growx"
} )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "iconsLabel"
+ "text": "Leading/trailing icons:"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 14"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "leadingIconTextField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 14,growx"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "trailingIconTextField"
+ "text": "text"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 14,growx"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "iconsTextField"
+ "text": "text"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 3 14,growx"
+ } )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
- "size": new java.awt.Dimension( 920, 440 )
+ "size": new java.awt.Dimension( 920, 480 )
} )
add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) {
name: "popupMenu1"
diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/DataTables.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/DataTables.svg
new file mode 100644
index 00000000..f69b635f
--- /dev/null
+++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/DataTables.svg
@@ -0,0 +1,8 @@
+
+
diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/bookmarkGroup.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/bookmarkGroup.svg
new file mode 100644
index 00000000..c1fe3f6c
--- /dev/null
+++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/bookmarkGroup.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/user.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/user.svg
new file mode 100644
index 00000000..a073a132
--- /dev/null
+++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/user.svg
@@ -0,0 +1,4 @@
+
+
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 4ebc554d..0201e024 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
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.extras.components;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.Color;
import java.awt.Insets;
+import javax.swing.Icon;
import javax.swing.JFormattedTextField;
import com.formdev.flatlaf.extras.components.FlatTextField.SelectAllOnFocusPolicy;
@@ -46,6 +47,44 @@ public class FlatFormattedTextField
}
+ /**
+ * Returns the leading icon that will be placed at the leading edge of the text field.
+ *
+ * @since 2
+ */
+ public Icon getLeadingIcon() {
+ return (Icon) getClientProperty( TEXT_FIELD_LEADING_ICON );
+ }
+
+ /**
+ * Specifies the leading icon that will be placed at the leading edge of the text field.
+ *
+ * @since 2
+ */
+ public void setLeadingIcon( Icon leadingIcon ) {
+ putClientProperty( TEXT_FIELD_LEADING_ICON, leadingIcon );
+ }
+
+
+ /**
+ * Returns the trailing icon that will be placed at the trailing edge of the text field.
+ *
+ * @since 2
+ */
+ public Icon getTrailingIcon() {
+ return (Icon) getClientProperty( TEXT_FIELD_TRAILING_ICON );
+ }
+
+ /**
+ * Specifies the trailing icon that will be placed at the trailing edge of the text field.
+ *
+ * @since 2
+ */
+ public void setTrailingIcon( Icon trailingIcon ) {
+ putClientProperty( TEXT_FIELD_TRAILING_ICON, trailingIcon );
+ }
+
+
/**
* 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 86495da2..4489e259 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
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.extras.components;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.Color;
import java.awt.Insets;
+import javax.swing.Icon;
import javax.swing.JPasswordField;
import com.formdev.flatlaf.extras.components.FlatTextField.SelectAllOnFocusPolicy;
@@ -46,6 +47,44 @@ public class FlatPasswordField
}
+ /**
+ * Returns the leading icon that will be placed at the leading edge of the text field.
+ *
+ * @since 2
+ */
+ public Icon getLeadingIcon() {
+ return (Icon) getClientProperty( TEXT_FIELD_LEADING_ICON );
+ }
+
+ /**
+ * Specifies the leading icon that will be placed at the leading edge of the text field.
+ *
+ * @since 2
+ */
+ public void setLeadingIcon( Icon leadingIcon ) {
+ putClientProperty( TEXT_FIELD_LEADING_ICON, leadingIcon );
+ }
+
+
+ /**
+ * Returns the trailing icon that will be placed at the trailing edge of the text field.
+ *
+ * @since 2
+ */
+ public Icon getTrailingIcon() {
+ return (Icon) getClientProperty( TEXT_FIELD_TRAILING_ICON );
+ }
+
+ /**
+ * Specifies the trailing icon that will be placed at the trailing edge of the text field.
+ *
+ * @since 2
+ */
+ public void setTrailingIcon( Icon trailingIcon ) {
+ putClientProperty( TEXT_FIELD_TRAILING_ICON, trailingIcon );
+ }
+
+
/**
* 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 bfa22dd2..99627cf4 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
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.extras.components;
import static com.formdev.flatlaf.FlatClientProperties.*;
import java.awt.Color;
import java.awt.Insets;
+import javax.swing.Icon;
import javax.swing.JTextField;
/**
@@ -45,6 +46,44 @@ public class FlatTextField
}
+ /**
+ * Returns the leading icon that will be placed at the leading edge of the text field.
+ *
+ * @since 2
+ */
+ public Icon getLeadingIcon() {
+ return (Icon) getClientProperty( TEXT_FIELD_LEADING_ICON );
+ }
+
+ /**
+ * Specifies the leading icon that will be placed at the leading edge of the text field.
+ *
+ * @since 2
+ */
+ public void setLeadingIcon( Icon leadingIcon ) {
+ putClientProperty( TEXT_FIELD_LEADING_ICON, leadingIcon );
+ }
+
+
+ /**
+ * Returns the trailing icon that will be placed at the trailing edge of the text field.
+ *
+ * @since 2
+ */
+ public Icon getTrailingIcon() {
+ return (Icon) getClientProperty( TEXT_FIELD_TRAILING_ICON );
+ }
+
+ /**
+ * Specifies the trailing icon that will be placed at the trailing edge of the text field.
+ *
+ * @since 2
+ */
+ public void setTrailingIcon( Icon trailingIcon ) {
+ putClientProperty( TEXT_FIELD_TRAILING_ICON, trailingIcon );
+ }
+
+
// 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_202.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt
index 2f401fdc..2a1fc74e 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt
@@ -311,6 +311,7 @@ FormattedTextField.caretForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.
FormattedTextField.disabledBackground #3c3f41 HSL 204 4 25 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.font [active] $defaultFont [UI]
FormattedTextField.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
+FormattedTextField.iconTextGap 4
FormattedTextField.inactiveBackground #3c3f41 HSL 204 4 25 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.inactiveForeground #888888 HSL 0 0 53 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
@@ -699,6 +700,7 @@ PasswordField.disabledBackground #3c3f41 HSL 204 4 25 javax.swing.plaf.Co
PasswordField.echoChar '\u2022'
PasswordField.font [active] $defaultFont [UI]
PasswordField.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
+PasswordField.iconTextGap 4
PasswordField.inactiveBackground #3c3f41 HSL 204 4 25 javax.swing.plaf.ColorUIResource [UI]
PasswordField.inactiveForeground #888888 HSL 0 0 53 javax.swing.plaf.ColorUIResource [UI]
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
@@ -1155,6 +1157,7 @@ TextField.disabledBackground #3c3f41 HSL 204 4 25 javax.swing.plaf.Colo
TextField.font [active] $defaultFont [UI]
TextField.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
TextField.highlight #242424 HSL 0 0 14 javax.swing.plaf.ColorUIResource [UI]
+TextField.iconTextGap 4
TextField.inactiveBackground #3c3f41 HSL 204 4 25 javax.swing.plaf.ColorUIResource [UI]
TextField.inactiveForeground #888888 HSL 0 0 53 javax.swing.plaf.ColorUIResource [UI]
TextField.light #313131 HSL 0 0 19 javax.swing.plaf.ColorUIResource [UI]
diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt
index d3942343..02dee1f4 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt
@@ -315,6 +315,7 @@ FormattedTextField.caretForeground #000000 HSL 0 0 0 javax.swing.plaf.
FormattedTextField.disabledBackground #f2f2f2 HSL 0 0 95 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.font [active] $defaultFont [UI]
FormattedTextField.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
+FormattedTextField.iconTextGap 4
FormattedTextField.inactiveBackground #f2f2f2 HSL 0 0 95 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
@@ -704,6 +705,7 @@ PasswordField.disabledBackground #f2f2f2 HSL 0 0 95 javax.swing.plaf.Co
PasswordField.echoChar '\u2022'
PasswordField.font [active] $defaultFont [UI]
PasswordField.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
+PasswordField.iconTextGap 4
PasswordField.inactiveBackground #f2f2f2 HSL 0 0 95 javax.swing.plaf.ColorUIResource [UI]
PasswordField.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
@@ -1160,6 +1162,7 @@ TextField.disabledBackground #f2f2f2 HSL 0 0 95 javax.swing.plaf.Colo
TextField.font [active] $defaultFont [UI]
TextField.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
TextField.highlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
+TextField.iconTextGap 4
TextField.inactiveBackground #f2f2f2 HSL 0 0 95 javax.swing.plaf.ColorUIResource [UI]
TextField.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.ColorUIResource [UI]
TextField.light #e3e3e3 HSL 0 0 89 javax.swing.plaf.ColorUIResource [UI]
diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt
index 40d64308..5ce617d7 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt
@@ -311,6 +311,7 @@ FormattedTextField.disabledBackground #e0e0e0 HSL 0 0 88 javax.swing.pl
FormattedTextField.focusedBackground #ffff88 HSL 60 100 77 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.font [active] $defaultFont [UI]
FormattedTextField.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
+FormattedTextField.iconTextGap 4
FormattedTextField.inactiveBackground #f0f0f0 HSL 0 0 94 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.inactiveForeground #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
FormattedTextField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
@@ -708,6 +709,7 @@ PasswordField.echoChar '\u2022'
PasswordField.focusedBackground #ffff88 HSL 60 100 77 javax.swing.plaf.ColorUIResource [UI]
PasswordField.font [active] $defaultFont [UI]
PasswordField.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
+PasswordField.iconTextGap 4
PasswordField.inactiveBackground #f0f0f0 HSL 0 0 94 javax.swing.plaf.ColorUIResource [UI]
PasswordField.inactiveForeground #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
PasswordField.margin 2,6,2,6 javax.swing.plaf.InsetsUIResource [UI]
@@ -1167,6 +1169,7 @@ TextField.focusedBackground #ffff88 HSL 60 100 77 javax.swing.plaf.Colo
TextField.font [active] $defaultFont [UI]
TextField.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
TextField.highlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
+TextField.iconTextGap 4
TextField.inactiveBackground #f0f0f0 HSL 0 0 94 javax.swing.plaf.ColorUIResource [UI]
TextField.inactiveForeground #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI]
TextField.light #e3e3e3 HSL 0 0 89 javax.swing.plaf.ColorUIResource [UI]
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 24ebced1..73e3af9a 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
@@ -16,13 +16,16 @@
package com.formdev.flatlaf.testing;
+import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.text.DefaultEditorKit;
import com.formdev.flatlaf.FlatClientProperties;
+import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*;
/**
@@ -61,6 +64,23 @@ public class FlatTextComponentsTest
}
}
+ private void leadingIcon() {
+ applyIcon( FlatClientProperties.TEXT_FIELD_LEADING_ICON, leadingIconCheckBox.isSelected()
+ ? new TestIcon( 8, 16, Color.blue ) : null );
+ }
+
+ private void trailingIcon() {
+ applyIcon( FlatClientProperties.TEXT_FIELD_TRAILING_ICON, trailingIconCheckBox.isSelected()
+ ? new TestIcon( 24, 12, Color.magenta ) : null );
+ }
+
+ private void applyIcon( String key, Icon icon ) {
+ for( Component c : getComponents() ) {
+ if( c instanceof JTextField )
+ ((JTextField)c).putClientProperty( key, icon );
+ }
+ }
+
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel textFieldLabel = new JLabel();
@@ -80,6 +100,8 @@ public class FlatTextComponentsTest
topPaddingField = new JSpinner();
JLabel bottomPaddingLabel = new JLabel();
bottomPaddingField = new JSpinner();
+ leadingIconCheckBox = new JCheckBox();
+ trailingIconCheckBox = new JCheckBox();
JLabel passwordFieldLabel = new JLabel();
JPasswordField passwordField1 = new JPasswordField();
JPasswordField passwordField3 = new JPasswordField();
@@ -158,12 +180,14 @@ public class FlatTextComponentsTest
//---- textField1 ----
textField1.setText("editable");
textField1.setComponentPopupMenu(popupMenu1);
+ textField1.putClientProperty("JTextField.placeholderText", "place");
textField1.setName("textField1");
add(textField1, "cell 1 0,growx");
//---- textField3 ----
textField3.setText("longer text for testing horizontal scrolling");
textField3.setComponentPopupMenu(popupMenu1);
+ textField3.putClientProperty("JTextField.placeholderText", "place");
textField3.setName("textField3");
add(textField3, "cell 2 0,growx");
@@ -172,6 +196,7 @@ public class FlatTextComponentsTest
textField2.setSelectionStart(1);
textField2.setSelectionEnd(4);
textField2.setComponentPopupMenu(popupMenu1);
+ textField2.putClientProperty("JTextField.placeholderText", "place");
textField2.setName("textField2");
add(textField2, "cell 3 0");
@@ -185,12 +210,14 @@ public class FlatTextComponentsTest
//---- formattedTextField1 ----
formattedTextField1.setText("editable");
formattedTextField1.setComponentPopupMenu(popupMenu1);
+ formattedTextField1.putClientProperty("JTextField.placeholderText", "place");
formattedTextField1.setName("formattedTextField1");
add(formattedTextField1, "cell 1 1,growx");
//---- formattedTextField3 ----
formattedTextField3.setText("longer text for testing horizontal scrolling");
formattedTextField3.setComponentPopupMenu(popupMenu1);
+ formattedTextField3.putClientProperty("JTextField.placeholderText", "place");
formattedTextField3.setName("formattedTextField3");
add(formattedTextField3, "cell 2 1,growx");
@@ -208,6 +235,8 @@ public class FlatTextComponentsTest
"[]" +
"[]" +
"[]" +
+ "[]" +
+ "[]" +
"[]"));
//---- button1 ----
@@ -255,6 +284,18 @@ public class FlatTextComponentsTest
bottomPaddingField.setName("bottomPaddingField");
bottomPaddingField.addChangeListener(e -> paddingChanged());
panel1.add(bottomPaddingField, "cell 1 4");
+
+ //---- leadingIconCheckBox ----
+ leadingIconCheckBox.setText("leading icon");
+ leadingIconCheckBox.setName("leadingIconCheckBox");
+ leadingIconCheckBox.addActionListener(e -> leadingIcon());
+ panel1.add(leadingIconCheckBox, "cell 0 5 2 1,alignx left,growx 0");
+
+ //---- trailingIconCheckBox ----
+ trailingIconCheckBox.setText("trailing icon");
+ trailingIconCheckBox.setName("trailingIconCheckBox");
+ trailingIconCheckBox.addActionListener(e -> trailingIcon());
+ panel1.add(trailingIconCheckBox, "cell 0 6 2 1,alignx left,growx 0");
}
add(panel1, "cell 4 0 1 6,aligny top,growy 0");
@@ -268,12 +309,14 @@ public class FlatTextComponentsTest
//---- passwordField1 ----
passwordField1.setText("editable");
passwordField1.setComponentPopupMenu(popupMenu1);
+ passwordField1.putClientProperty("JTextField.placeholderText", "place");
passwordField1.setName("passwordField1");
add(passwordField1, "cell 1 2,growx");
//---- passwordField3 ----
passwordField3.setText("longer text for testing horizontal scrolling");
passwordField3.setComponentPopupMenu(popupMenu1);
+ passwordField3.putClientProperty("JTextField.placeholderText", "place");
passwordField3.setName("passwordField3");
add(passwordField3, "cell 2 2,growx");
@@ -508,5 +551,39 @@ public class FlatTextComponentsTest
private JSpinner rightPaddingField;
private JSpinner topPaddingField;
private JSpinner bottomPaddingField;
+ private JCheckBox leadingIconCheckBox;
+ private JCheckBox trailingIconCheckBox;
// JFormDesigner - End of variables declaration //GEN-END:variables
+
+ //---- TestIcon -----------------------------------------------------------
+
+ private static class TestIcon
+ implements Icon
+ {
+ private final int width;
+ private final int height;
+ private final Color color;
+
+ TestIcon( int width, int height, Color color ) {
+ this.width = width;
+ this.height = height;
+ this.color = color;
+ }
+
+ @Override
+ public void paintIcon( Component c, Graphics g, int x, int y ) {
+ g.setColor( color );
+ g.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 );
+ }
+
+ @Override
+ public int getIconWidth() {
+ return UIScale.scale( width );
+ }
+
+ @Override
+ public int getIconHeight() {
+ return UIScale.scale( height );
+ }
+ }
}
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 8ea38154..c26f61e4 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
@@ -25,6 +25,7 @@ new FormModel {
name: "textField1"
"text": "editable"
"componentPopupMenu": &FormReference0 new FormReference( "popupMenu1" )
+ "$client.JTextField.placeholderText": "place"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -35,6 +36,7 @@ new FormModel {
name: "textField3"
"text": "longer text for testing horizontal scrolling"
"componentPopupMenu": #FormReference0
+ "$client.JTextField.placeholderText": "place"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0,growx"
} )
@@ -44,6 +46,7 @@ new FormModel {
"selectionStart": 1
"selectionEnd": 4
"componentPopupMenu": #FormReference0
+ "$client.JTextField.placeholderText": "place"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 0"
} )
@@ -59,6 +62,7 @@ new FormModel {
name: "formattedTextField1"
"text": "editable"
"componentPopupMenu": #FormReference0
+ "$client.JTextField.placeholderText": "place"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1,growx"
} )
@@ -66,13 +70,14 @@ new FormModel {
name: "formattedTextField3"
"text": "longer text for testing horizontal scrolling"
"componentPopupMenu": #FormReference0
+ "$client.JTextField.placeholderText": "place"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 1,growx"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3"
"$columnConstraints": "[fill][fill]"
- "$rowConstraints": "[][][][][]"
+ "$rowConstraints": "[][][][][][][]"
} ) {
name: "panel1"
"border": new javax.swing.border.TitledBorder( "Control" )
@@ -143,6 +148,26 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4"
} )
+ add( new FormComponent( "javax.swing.JCheckBox" ) {
+ name: "leadingIconCheckBox"
+ "text": "leading icon"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "leadingIcon", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 5 2 1,alignx left,growx 0"
+ } )
+ add( new FormComponent( "javax.swing.JCheckBox" ) {
+ name: "trailingIconCheckBox"
+ "text": "trailing icon"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "trailingIcon", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 6 2 1,alignx left,growx 0"
+ } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 0 1 6,aligny top,growy 0"
} )
@@ -158,6 +183,7 @@ new FormModel {
name: "passwordField1"
"text": "editable"
"componentPopupMenu": #FormReference0
+ "$client.JTextField.placeholderText": "place"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2,growx"
} )
@@ -165,6 +191,7 @@ new FormModel {
name: "passwordField3"
"text": "longer text for testing horizontal scrolling"
"componentPopupMenu": #FormReference0
+ "$client.JTextField.placeholderText": "place"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 2,growx"
} )
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 c50e3328..47e37e9f 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
@@ -241,6 +241,7 @@ FormattedTextField.focusInputMap
FormattedTextField.focusedBackground
FormattedTextField.font
FormattedTextField.foreground
+FormattedTextField.iconTextGap
FormattedTextField.inactiveBackground
FormattedTextField.inactiveForeground
FormattedTextField.margin
@@ -523,6 +524,7 @@ PasswordField.focusInputMap
PasswordField.focusedBackground
PasswordField.font
PasswordField.foreground
+PasswordField.iconTextGap
PasswordField.inactiveBackground
PasswordField.inactiveForeground
PasswordField.margin
@@ -884,6 +886,7 @@ TextField.focusedBackground
TextField.font
TextField.foreground
TextField.highlight
+TextField.iconTextGap
TextField.inactiveBackground
TextField.inactiveForeground
TextField.light