From 3e14f28dc26ec89cc270d1455eb5daebb3daeb96 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Fri, 2 Jul 2021 18:43:37 +0200 Subject: [PATCH] ComboBox (editable) and Spinner: increased size of internal text field to the component border so that it behaves like plain text field (issue #330) --- CHANGELOG.md | 6 +- .../formdev/flatlaf/ui/FlatComboBoxUI.java | 26 ++++--- .../com/formdev/flatlaf/ui/FlatSpinnerUI.java | 17 +++-- .../testing/FlatCustomBordersTest.java | 67 +++++++++++++++++++ .../flatlaf/testing/FlatCustomBordersTest.jfd | 53 ++++++++++++++- 5 files changed, 153 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1debe25..c81f6e4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,11 @@ FlatLaf Change Log #### Fixed bugs -- TBD +- ComboBox (editable) and Spinner: Increased size of internal text field to the + component border so that it behaves like plain text field (mouse click to left + of text now positions caret to first character instead of opening ComboBox + popup; mouse cursor is now of type "text" within the whole component, except + for arrow buttons). (issue #330) ## 1.3 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index 7616d1f8..1851d657 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java @@ -133,6 +133,8 @@ public class FlatComboBoxUI protected Color popupBackground; + protected Insets paddingUnscaled; + private MouseListener hoverListener; protected boolean hover; protected boolean pressed; @@ -223,7 +225,8 @@ public class FlatComboBoxUI comboBox.setMaximumRowCount( maximumRowCount ); // scale - padding = UIScale.scale( padding ); + paddingUnscaled = padding; + padding = UIScale.scale( paddingUnscaled ); MigLayoutVisualPadding.install( comboBox ); } @@ -276,11 +279,6 @@ public class FlatComboBoxUI editor.setBounds( rectangleForCurrentValue() ); } } - - if( editor != null && padding != null ) { - // fix editor bounds by subtracting padding - editor.setBounds( FlatUIUtils.subtractInsets( editor.getBounds(), padding ) ); - } } }; } @@ -361,9 +359,16 @@ public class FlatComboBoxUI protected void configureEditor() { super.configureEditor(); - // remove default text field border from editor - if( editor instanceof JTextField && ((JTextField)editor).getBorder() instanceof FlatTextBorder ) - ((JTextField)editor).setBorder( BorderFactory.createEmptyBorder() ); + if( editor instanceof JTextField ) { + JTextField textField = (JTextField) editor; + + // remove default text field border from editor + if( textField.getBorder() instanceof FlatTextBorder ) + textField.setBorder( BorderFactory.createEmptyBorder() ); + + // editor padding + textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, paddingUnscaled ); + } // explicitly make non-opaque if( editor instanceof JComponent ) @@ -548,6 +553,9 @@ public class FlatComboBoxUI ListCellRenderer renderer = comboBox.getRenderer(); uninstallCellPaddingBorder( renderer ); + // update padding + padding = UIScale.scale( paddingUnscaled ); + Dimension displaySize = super.getDisplaySize(); // recalculate width without hardcoded 100 under special conditions diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java index b5a35f66..d7238d90 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSpinnerUI.java @@ -123,9 +123,6 @@ public class FlatSpinnerUI buttonPressedArrowColor = UIManager.getColor( "Spinner.buttonPressedArrowColor" ); padding = UIManager.getInsets( "Spinner.padding" ); - // scale - padding = scale( padding ); - MigLayoutVisualPadding.install( spinner ); } @@ -184,6 +181,7 @@ public class FlatSpinnerUI if( textField != null ) textField.setOpaque( false ); + updateEditorPadding(); updateEditorColors(); return editor; } @@ -194,6 +192,8 @@ public class FlatSpinnerUI removeEditorFocusListener( oldEditor ); addEditorFocusListener( newEditor ); + + updateEditorPadding(); updateEditorColors(); } @@ -209,6 +209,12 @@ public class FlatSpinnerUI textField.removeFocusListener( getHandler() ); } + private void updateEditorPadding() { + JTextField textField = getEditorTextField( spinner.getEditor() ); + if( textField != null ) + textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, padding ); + } + private void updateEditorColors() { JTextField textField = getEditorTextField( spinner.getEditor() ); if( textField != null ) { @@ -373,6 +379,7 @@ public class FlatSpinnerUI @Override public Dimension preferredLayoutSize( Container parent ) { Insets insets = parent.getInsets(); + Insets padding = scale( FlatSpinnerUI.this.padding ); Dimension editorSize = (editor != null) ? editor.getPreferredSize() : new Dimension( 0, 0 ); // the arrows width is the same as the inner height so that the arrows area is square @@ -397,7 +404,7 @@ public class FlatSpinnerUI if( nextButton == null && previousButton == null ) { if( editor != null ) - editor.setBounds( FlatUIUtils.subtractInsets( r, padding ) ); + editor.setBounds( r ); return; } @@ -417,7 +424,7 @@ public class FlatSpinnerUI } if( editor != null ) - editor.setBounds( FlatUIUtils.subtractInsets( editorRect, padding ) ); + editor.setBounds( editorRect ); int nextHeight = (buttonsRect.height / 2) + (buttonsRect.height % 2); // round up if( nextButton != null ) diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatCustomBordersTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatCustomBordersTest.java index 18c5a0cb..b2734209 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatCustomBordersTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatCustomBordersTest.java @@ -20,6 +20,7 @@ import java.awt.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.plaf.basic.BasicComboBoxEditor; +import javax.swing.plaf.basic.BasicComboBoxRenderer; import com.formdev.flatlaf.icons.FlatFileViewFloppyDriveIcon; import com.formdev.flatlaf.util.UIScale; import net.miginfocom.swing.*; @@ -42,9 +43,23 @@ public class FlatCustomBordersTest } ); } + @SuppressWarnings( "unchecked" ) FlatCustomBordersTest() { initComponents(); applyCustomBorders(); + + DefaultComboBoxModel model = new DefaultComboBoxModel<>( new String[] { + "text", + "123", + "4567", + "abc", + "def" + } ); + + for( Component c : getComponents() ) { + if( c instanceof JComboBox ) + ((JComboBox)c).setModel( model ); + } } @Override @@ -99,6 +114,13 @@ public class FlatCustomBordersTest applyCustomComboBoxEditorBorderWithIcon( comboBox20 ); applyCustomComboBoxEditorBorder( comboBox21, null ); applyCustomComboBoxEditorBorder( comboBox22, null ); + + applyCustomComboBoxRendererBorder( comboBox23 ); + applyCustomComboBoxRendererBorder( comboBox24 ); + applyCustomComboBoxRendererBorderWithIcon( comboBox25 ); + applyCustomComboBoxRendererBorderWithIcon( comboBox26 ); + applyCustomComboBoxRendererBorder( comboBox27, null ); + applyCustomComboBoxRendererBorder( comboBox28, null ); } private void applyCustomInsideBorder( JComponent c, String uiKey ) { @@ -129,6 +151,21 @@ public class FlatCustomBordersTest } ); } + private void applyCustomComboBoxRendererBorder( JComboBox comboBox ) { + applyCustomComboBoxRendererBorder( comboBox, new LineBorder( ORANGE, UIScale.scale( 3 ) ) ); + } + + private void applyCustomComboBoxRendererBorderWithIcon( JComboBox comboBox ) { + applyCustomComboBoxRendererBorder( comboBox, new BorderWithIcon() ); + } + + @SuppressWarnings( "unchecked" ) + private void applyCustomComboBoxRendererBorder( JComboBox comboBox, Border border ) { + BasicComboBoxRenderer customRenderer = new BasicComboBoxRenderer(); + customRenderer.setBorder( border ); + comboBox.setRenderer( customRenderer ); + } + private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents label1 = new JLabel(); @@ -152,10 +189,16 @@ public class FlatCustomBordersTest comboBox2 = new JComboBox<>(); comboBox3 = new JComboBox<>(); comboBox4 = new JComboBox<>(); + comboBox23 = new JComboBox<>(); + comboBox25 = new JComboBox<>(); + comboBox27 = new JComboBox<>(); comboBox5 = new JComboBox<>(); comboBox6 = new JComboBox<>(); comboBox7 = new JComboBox<>(); comboBox8 = new JComboBox<>(); + comboBox24 = new JComboBox<>(); + comboBox26 = new JComboBox<>(); + comboBox28 = new JComboBox<>(); comboBox9 = new JComboBox<>(); comboBox10 = new JComboBox<>(); comboBox11 = new JComboBox<>(); @@ -289,6 +332,9 @@ public class FlatCustomBordersTest add(comboBox2, "cell 2 3"); add(comboBox3, "cell 3 3"); add(comboBox4, "cell 4 3"); + add(comboBox23, "cell 5 3"); + add(comboBox25, "cell 6 3"); + add(comboBox27, "cell 7 3"); //---- comboBox5 ---- comboBox5.putClientProperty("JComponent.roundRect", true); @@ -306,6 +352,18 @@ public class FlatCustomBordersTest comboBox8.putClientProperty("JComponent.roundRect", true); add(comboBox8, "cell 4 4"); + //---- comboBox24 ---- + comboBox24.putClientProperty("JComponent.roundRect", true); + add(comboBox24, "cell 5 4"); + + //---- comboBox26 ---- + comboBox26.putClientProperty("JComponent.roundRect", true); + add(comboBox26, "cell 6 4"); + + //---- comboBox28 ---- + comboBox28.putClientProperty("JComponent.roundRect", true); + add(comboBox28, "cell 7 4"); + //---- comboBox9 ---- comboBox9.setEditable(true); add(comboBox9, "cell 1 5"); @@ -460,10 +518,16 @@ public class FlatCustomBordersTest private JComboBox comboBox2; private JComboBox comboBox3; private JComboBox comboBox4; + private JComboBox comboBox23; + private JComboBox comboBox25; + private JComboBox comboBox27; private JComboBox comboBox5; private JComboBox comboBox6; private JComboBox comboBox7; private JComboBox comboBox8; + private JComboBox comboBox24; + private JComboBox comboBox26; + private JComboBox comboBox28; private JComboBox comboBox9; private JComboBox comboBox10; private JComboBox comboBox11; @@ -508,6 +572,9 @@ public class FlatCustomBordersTest @Override public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { icon.paintIcon( c, g, x + width - icon.getIconWidth() - 2, y + ((height - icon.getIconHeight()) / 2) ); + + g.setColor( RED ); + g.drawRect( x, y, width - 1, height - 1 ); } @Override diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatCustomBordersTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatCustomBordersTest.jfd index 36dea94b..6d67ea4a 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatCustomBordersTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatCustomBordersTest.jfd @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.2.0.298" Java: "15" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -147,6 +147,30 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 4 3" } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox23" + auxiliary() { + "JavaCodeGenerator.typeParameters": "String" + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 5 3" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox25" + auxiliary() { + "JavaCodeGenerator.typeParameters": "String" + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 6 3" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox27" + auxiliary() { + "JavaCodeGenerator.typeParameters": "String" + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 7 3" + } ) add( new FormComponent( "javax.swing.JComboBox" ) { name: "comboBox5" "$client.JComponent.roundRect": true @@ -183,6 +207,33 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 4 4" } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox24" + "$client.JComponent.roundRect": true + auxiliary() { + "JavaCodeGenerator.typeParameters": "String" + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 5 4" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox26" + "$client.JComponent.roundRect": true + auxiliary() { + "JavaCodeGenerator.typeParameters": "String" + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 6 4" + } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox28" + "$client.JComponent.roundRect": true + auxiliary() { + "JavaCodeGenerator.typeParameters": "String" + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 7 4" + } ) add( new FormComponent( "javax.swing.JComboBox" ) { name: "comboBox9" "editable": true