From a9dcf09d1312743519c9874fb450f8ac2542856d Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 2 Jul 2021 15:19:46 +0200 Subject: [PATCH] TextField: support adding extra padding (for #172, #173 and #330) --- CHANGELOG.md | 2 + .../formdev/flatlaf/FlatClientProperties.java | 12 ++ .../com/formdev/flatlaf/ui/FlatCaret.java | 15 +++ .../formdev/flatlaf/ui/FlatTextFieldUI.java | 26 +++++ .../testing/FlatTextComponentsTest.java | 106 ++++++++++++++++-- .../testing/FlatTextComponentsTest.jfd | 88 +++++++++++++-- 6 files changed, 232 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eff57deb..a1debe25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ FlatLaf Change Log #### New features and improvements +- TextField, FormattedTextField and PasswordField: Support adding extra padding. + (set client property `JTextField.padding` to `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 ff6a5aa5..dace152f 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -733,6 +733,18 @@ public interface FlatClientProperties */ String PLACEHOLDER_TEXT = "JTextField.placeholderText"; + /** + * Specifies the padding of the text. + * This changes the location and size of the text view within the component bounds, + * but does not affect the size of the component. + *

+ * Component {@link javax.swing.JTextField} (and subclasses)
+ * Value type {@link java.awt.Insets} + * + * @since 1.4 + */ + String TEXT_FIELD_PADDING = "JTextField.padding"; + //---- JToggleButton ------------------------------------------------------ /** 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 ba52ff4f..fe28e1c0 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,6 +18,8 @@ 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; import javax.swing.JFormattedTextField; @@ -61,6 +63,19 @@ public class FlatCaret } } + @Override + 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; + } + } + super.adjustVisibility( nloc ); + } + @Override public void focusGained( FocusEvent e ) { if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) ) 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 28bf85a5..8e9db66b 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 @@ -24,6 +24,7 @@ import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.Rectangle; import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; import javax.swing.JComboBox; @@ -40,6 +41,7 @@ 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}. @@ -142,6 +144,7 @@ public class FlatTextFieldUI switch( e.getPropertyName() ) { case FlatClientProperties.PLACEHOLDER_TEXT: case FlatClientProperties.COMPONENT_ROUND_RECT: + case FlatClientProperties.TEXT_FIELD_PADDING: c.repaint(); break; @@ -264,4 +267,27 @@ public class FlatTextFieldUI size.width = Math.max( size.width, scale( minimumWidth ) + Math.round( focusWidth * 2 ) ); return size; } + + @Override + protected Rectangle getVisibleEditorRect() { + 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 ); + } + } + return r; + } + + /** + * @since 1.4 + */ + protected Insets getPadding() { + Object padding = getComponent().getClientProperty( FlatClientProperties.TEXT_FIELD_PADDING ); + return (padding instanceof Insets) ? UIScale.scale( (Insets) padding ) : null; + } } 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 80b68989..ecb55f42 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,8 +16,12 @@ package com.formdev.flatlaf.testing; +import java.awt.Component; +import java.awt.Insets; import javax.swing.*; +import javax.swing.border.*; import javax.swing.text.DefaultEditorKit; +import com.formdev.flatlaf.FlatClientProperties; import net.miginfocom.swing.*; /** @@ -41,16 +45,40 @@ public class FlatTextComponentsTest textField1.setText( "new text" ); } + private void paddingChanged() { + Insets padding = new Insets( + (int) topPaddingField.getValue(), + (int) leftPaddingField.getValue(), + (int) bottomPaddingField.getValue(), + (int) rightPaddingField.getValue() ); + if( padding.equals( new Insets( 0, 0, 0, 0 ) ) ) + padding = null; + + for( Component c : getComponents() ) { + if( c instanceof JTextField ) + ((JTextField)c).putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, padding ); + } + } + private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents JLabel textFieldLabel = new JLabel(); textField1 = new JTextField(); JTextField textField3 = new JTextField(); JTextField textField2 = new JTextField(); - JButton button1 = new JButton(); JLabel formattedTextFieldLabel = new JLabel(); JFormattedTextField formattedTextField1 = new JFormattedTextField(); JFormattedTextField formattedTextField3 = new JFormattedTextField(); + JPanel panel1 = new JPanel(); + JButton button1 = new JButton(); + JLabel leftPaddingLabel = new JLabel(); + leftPaddingField = new JSpinner(); + JLabel rightPaddingLabel = new JLabel(); + rightPaddingField = new JSpinner(); + JLabel topPaddingLabel = new JLabel(); + topPaddingField = new JSpinner(); + JLabel bottomPaddingLabel = new JLabel(); + bottomPaddingField = new JSpinner(); JLabel passwordFieldLabel = new JLabel(); JPasswordField passwordField1 = new JPasswordField(); JPasswordField passwordField3 = new JPasswordField(); @@ -134,12 +162,6 @@ public class FlatTextComponentsTest textField2.setName("textField2"); add(textField2, "cell 3 0"); - //---- button1 ---- - button1.setText("change text"); - button1.setName("button1"); - button1.addActionListener(e -> changeText()); - add(button1, "cell 4 0"); - //---- formattedTextFieldLabel ---- formattedTextFieldLabel.setText("JFormattedTextField:"); formattedTextFieldLabel.setDisplayedMnemonic('F'); @@ -159,6 +181,70 @@ public class FlatTextComponentsTest formattedTextField3.setName("formattedTextField3"); add(formattedTextField3, "cell 2 1,growx"); + //======== panel1 ======== + { + panel1.setBorder(new TitledBorder("Control")); + panel1.setName("panel1"); + panel1.setLayout(new MigLayout( + "hidemode 3", + // columns + "[fill]" + + "[fill]", + // rows + "[]" + + "[]" + + "[]" + + "[]" + + "[]")); + + //---- button1 ---- + button1.setText("change text"); + button1.setName("button1"); + button1.addActionListener(e -> changeText()); + panel1.add(button1, "cell 0 0 2 1,alignx left,growx 0"); + + //---- leftPaddingLabel ---- + leftPaddingLabel.setText("Left padding:"); + leftPaddingLabel.setName("leftPaddingLabel"); + panel1.add(leftPaddingLabel, "cell 0 1"); + + //---- leftPaddingField ---- + leftPaddingField.setName("leftPaddingField"); + leftPaddingField.addChangeListener(e -> paddingChanged()); + panel1.add(leftPaddingField, "cell 1 1"); + + //---- rightPaddingLabel ---- + rightPaddingLabel.setText("Right padding:"); + rightPaddingLabel.setName("rightPaddingLabel"); + panel1.add(rightPaddingLabel, "cell 0 2"); + + //---- rightPaddingField ---- + rightPaddingField.setName("rightPaddingField"); + rightPaddingField.addChangeListener(e -> paddingChanged()); + panel1.add(rightPaddingField, "cell 1 2"); + + //---- topPaddingLabel ---- + topPaddingLabel.setText("Top padding:"); + topPaddingLabel.setName("topPaddingLabel"); + panel1.add(topPaddingLabel, "cell 0 3"); + + //---- topPaddingField ---- + topPaddingField.setName("topPaddingField"); + topPaddingField.addChangeListener(e -> paddingChanged()); + panel1.add(topPaddingField, "cell 1 3"); + + //---- bottomPaddingLabel ---- + bottomPaddingLabel.setText("Bottom padding:"); + bottomPaddingLabel.setName("bottomPaddingLabel"); + panel1.add(bottomPaddingLabel, "cell 0 4"); + + //---- bottomPaddingField ---- + bottomPaddingField.setName("bottomPaddingField"); + bottomPaddingField.addChangeListener(e -> paddingChanged()); + panel1.add(bottomPaddingField, "cell 1 4"); + } + add(panel1, "cell 4 0 1 6,aligny top,growy 0"); + //---- passwordFieldLabel ---- passwordFieldLabel.setText("JPasswordField:"); passwordFieldLabel.setDisplayedMnemonic('P'); @@ -301,7 +387,7 @@ public class FlatTextComponentsTest comboBox3.setPrototypeDisplayValue("12345"); comboBox3.setComponentPopupMenu(popupMenu1); comboBox3.setName("comboBox3"); - add(comboBox3, "cell 2 6,growx"); + add(comboBox3, "cell 2 6,growx,wmin 50"); //---- spinnerLabel ---- spinnerLabel.setText("JSpinner:"); @@ -361,5 +447,9 @@ public class FlatTextComponentsTest // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables private JTextField textField1; + private JSpinner leftPaddingField; + private JSpinner rightPaddingField; + private JSpinner topPaddingField; + private JSpinner bottomPaddingField; // JFormDesigner - End of variables declaration //GEN-END:variables } 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 aa4526b3..b8bcac13 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 @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.3.1.342" Java: "16" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -47,13 +47,6 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 3 0" } ) - add( new FormComponent( "javax.swing.JButton" ) { - name: "button1" - "text": "change text" - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeText", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 4 0" - } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "formattedTextFieldLabel" "text": "JFormattedTextField:" @@ -76,6 +69,83 @@ new FormModel { }, 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": "[][][][][]" + } ) { + name: "panel1" + "border": new javax.swing.border.TitledBorder( "Control" ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "button1" + "text": "change text" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeText", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0 2 1,alignx left,growx 0" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "leftPaddingLabel" + "text": "Left padding:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "leftPaddingField" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "paddingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "rightPaddingLabel" + "text": "Right padding:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "rightPaddingField" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "paddingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 2" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "topPaddingLabel" + "text": "Top padding:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "topPaddingField" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "paddingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "bottomPaddingLabel" + "text": "Bottom padding:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "bottomPaddingField" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "paddingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4" + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 0 1 6,aligny top,growy 0" + } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "passwordFieldLabel" "text": "JPasswordField:" @@ -217,7 +287,7 @@ new FormModel { "prototypeDisplayValue": "12345" "componentPopupMenu": #FormReference0 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 6,growx" + "value": "cell 2 6,growx,wmin 50" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "spinnerLabel"