diff --git a/CHANGELOG.md b/CHANGELOG.md index 12aafd35..1050dcf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ FlatLaf Change Log 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) +- ComboBox (not editable): Increased size of internal renderer pane to the + component border so that it can paint within the whole component. Also + increase combo box size if a custom renderer uses a border with insets that + are larger than the default combo box padding (`2,6,2,6`). - Fixed component heights at `1.25x`, `1.75x` and `2.25x` scaling factors (Java 8 only) so that Button, ComboBox, Spinner and TextField components (including subclasses) have same heights. This increases heights of Button and TextField 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 76bb0369..840a57bf 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 @@ -17,6 +17,7 @@ package com.formdev.flatlaf.ui; import static com.formdev.flatlaf.util.UIScale.scale; +import static com.formdev.flatlaf.util.UIScale.unscale; import java.awt.Color; import java.awt.Component; import java.awt.ComponentOrientation; @@ -67,7 +68,6 @@ import javax.swing.plaf.basic.ComboPopup; import javax.swing.text.JTextComponent; import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.util.SystemInfo; -import com.formdev.flatlaf.util.UIScale; /** * Provides the Flat LaF UI delegate for {@link javax.swing.JComboBox}. @@ -132,8 +132,6 @@ public class FlatComboBoxUI protected Color popupBackground; - protected Insets paddingUnscaled; - private MouseListener hoverListener; protected boolean hover; protected boolean pressed; @@ -223,10 +221,6 @@ public class FlatComboBoxUI if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 ) comboBox.setMaximumRowCount( maximumRowCount ); - // scale - paddingUnscaled = padding; - padding = UIScale.scale( paddingUnscaled ); - paddingBorder = new CellPaddingBorder( padding ); MigLayoutVisualPadding.install( comboBox ); @@ -368,9 +362,6 @@ public class FlatComboBoxUI // 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 @@ -379,6 +370,7 @@ public class FlatComboBoxUI editor.applyComponentOrientation( comboBox.getComponentOrientation() ); + updateEditorPadding(); updateEditorColors(); // macOS @@ -395,6 +387,25 @@ public class FlatComboBoxUI } } + private void updateEditorPadding() { + if( !(editor instanceof JTextField) ) + return; + + JTextField textField = (JTextField) editor; + Insets insets = textField.getInsets(); + Insets pad = padding; + if( insets.top != 0 || insets.left != 0 || insets.bottom != 0 || insets.right != 0 ) { + // if text field has custom border, subtract text field insets from padding + pad = new Insets( + unscale( Math.max( scale( padding.top ) - insets.top, 0 ) ), + unscale( Math.max( scale( padding.left ) - insets.left, 0 ) ), + unscale( Math.max( scale( padding.bottom ) - insets.bottom, 0 ) ), + unscale( Math.max( scale( padding.right ) - insets.right, 0 ) ) + ); + } + textField.putClientProperty( FlatClientProperties.TEXT_FIELD_PADDING, pad ); + } + private void updateEditorColors() { // use non-UIResource colors because when SwingUtilities.updateComponentTreeUI() // is used, then the editor is updated after the combobox and the @@ -493,16 +504,10 @@ public class FlatComboBoxUI c.setForeground( getForeground( enabled ) ); boolean shouldValidate = (c instanceof JPanel); - if( padding != null ) - bounds = FlatUIUtils.subtractInsets( bounds, padding ); - - // increase the size of the rendering area to make sure that the text - // is vertically aligned with other component types (e.g. JTextField) - Insets rendererInsets = getRendererComponentInsets( c ); - if( rendererInsets != null ) - bounds = FlatUIUtils.addInsets( bounds, rendererInsets ); + paddingBorder.install( c ); currentValuePane.paintComponent( g, c, comboBox, bounds.x, bounds.y, bounds.width, bounds.height, shouldValidate ); + paddingBorder.uninstall(); } @Override @@ -549,51 +554,35 @@ public class FlatComboBoxUI @Override protected Dimension getDisplaySize() { - // update padding - padding = UIScale.scale( paddingUnscaled ); paddingBorder.uninstall(); Dimension displaySize = super.getDisplaySize(); paddingBorder.uninstall(); + // remove padding added in super.getDisplaySize() + int displayWidth = displaySize.width - padding.left - padding.right; + int displayHeight = displaySize.height - padding.top - padding.bottom; + // recalculate width without hardcoded 100 under special conditions - if( displaySize.width == 100 + padding.left + padding.right && + if( displayWidth == 100 && comboBox.isEditable() && comboBox.getItemCount() == 0 && comboBox.getPrototypeDisplayValue() == null ) { - int width = getDefaultSize().width; - width = Math.max( width, editor.getPreferredSize().width ); - width += padding.left + padding.right; - displaySize = new Dimension( width, displaySize.height ); + displayWidth = Math.max( getDefaultSize().width, editor.getPreferredSize().width ); } - return displaySize; + return new Dimension( displayWidth, displayHeight ); } @Override protected Dimension getSizeForComponent( Component comp ) { + paddingBorder.install( comp ); Dimension size = super.getSizeForComponent( comp ); - - // remove the renderer border top/bottom insets from the size to make sure that - // the combobox gets the same height as other component types (e.g. JTextField) - Insets rendererInsets = getRendererComponentInsets( comp ); - if( rendererInsets != null ) - size = new Dimension( size.width, size.height - rendererInsets.top - rendererInsets.bottom ); - + paddingBorder.uninstall(); return size; } - private Insets getRendererComponentInsets( Component rendererComponent ) { - if( rendererComponent instanceof JComponent ) { - Border rendererBorder = ((JComponent)rendererComponent).getBorder(); - if( rendererBorder != null ) - return rendererBorder.getBorderInsets( rendererComponent ); - } - - return null; - } - private boolean isCellRenderer() { return comboBox.getParent() instanceof CellRendererPane; } @@ -661,7 +650,7 @@ public class FlatComboBoxUI super( combo ); // BasicComboPopup listens to JComboBox.componentOrientation and updates - // the component orientation of the list, scroller and popup, but when + // the component orientation of the list, scroll pane and popup, but when // switching the LaF and a new combo popup is created, the component // orientation is not applied. ComponentOrientation o = comboBox.getComponentOrientation(); @@ -780,7 +769,7 @@ public class FlatComboBoxUI //---- class CellPaddingBorder -------------------------------------------- /** - * Cell padding border used only in popup list. + * Cell padding border used in popup list and for current value if not editable. *

* The insets are the union of the cell padding and the renderer border insets, * which vertically aligns text in popup list with text in combobox. @@ -836,6 +825,7 @@ public class FlatComboBoxUI @Override public Insets getBorderInsets( Component c, Insets insets ) { + Insets padding = scale( this.padding ); if( rendererBorder != null ) { Insets insideInsets = rendererBorder.getBorderInsets( c ); insets.top = Math.max( padding.top, insideInsets.top ); diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatComponentSizes.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatComponentSizes.java index dbea872a..f88e53d7 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatComponentSizes.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatComponentSizes.java @@ -114,17 +114,19 @@ public class TestFlatComponentSizes void comboBox( float factor ) { TestUtils.scaleFont( factor ); - JComboBox comboBox = new JComboBox<>(); - JComboBox comboBox2 = new JComboBox<>(); - JComboBox comboBox3 = new JComboBox<>(); - JComboBox comboBox4 = new JComboBox<>(); + String[] items = { "text" }; + JComboBox comboBox = new JComboBox<>( items ); + JComboBox comboBox2 = new JComboBox<>( items ); + JComboBox comboBox3 = new JComboBox<>( items ); + JComboBox comboBox4 = new JComboBox<>( items ); - applyCustomComboBoxRendererBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 3 ) ) ); + applyCustomComboBoxRendererBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 6 ) ) ); applyCustomComboBoxRendererBorder( comboBox3, new BorderWithIcon() ); applyCustomComboBoxRendererBorder( comboBox4, null ); Dimension size = comboBox.getPreferredSize(); - assertEquals( size, comboBox2.getPreferredSize() ); + assertEquals( size.width, comboBox2.getPreferredSize().width ); + assertEquals( size.height - (2 * UIScale.scale( 2 )) + (2 * UIScale.scale( 6 )), comboBox2.getPreferredSize().height ); assertEquals( size, comboBox3.getPreferredSize() ); assertEquals( size, comboBox4.getPreferredSize() ); @@ -143,23 +145,24 @@ public class TestFlatComponentSizes void comboBoxEditable( float factor ) { TestUtils.scaleFont( factor ); - JComboBox comboBox = new JComboBox<>(); - JComboBox comboBox2 = new JComboBox<>(); - JComboBox comboBox3 = new JComboBox<>(); - JComboBox comboBox4 = new JComboBox<>(); + String[] items = { "text" }; + JComboBox comboBox = new JComboBox<>( items ); + JComboBox comboBox2 = new JComboBox<>( items ); + JComboBox comboBox3 = new JComboBox<>( items ); + JComboBox comboBox4 = new JComboBox<>( items ); comboBox.setEditable( true ); comboBox2.setEditable( true ); comboBox3.setEditable( true ); comboBox4.setEditable( true ); - applyCustomComboBoxEditorBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 3 ) ) ); + applyCustomComboBoxEditorBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 6 ) ) ); applyCustomComboBoxEditorBorder( comboBox3, new BorderWithIcon() ); applyCustomComboBoxEditorBorder( comboBox4, null ); Dimension size = comboBox.getPreferredSize(); assertEquals( size.width, comboBox2.getPreferredSize().width ); - assertEquals( size.height + (2 * UIScale.scale( 3 )), comboBox2.getPreferredSize().height ); + assertEquals( size.height - (2 * UIScale.scale( 2 )) + (2 * UIScale.scale( 6 )), comboBox2.getPreferredSize().height ); assertEquals( size, comboBox3.getPreferredSize() ); assertEquals( size, comboBox4.getPreferredSize() ); 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 b2734209..5f4c5478 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 @@ -132,7 +132,7 @@ public class FlatCustomBordersTest } private void applyCustomComboBoxEditorBorder( JComboBox comboBox ) { - applyCustomComboBoxEditorBorder( comboBox, new LineBorder( ORANGE, UIScale.scale( 3 ) ) ); + applyCustomComboBoxEditorBorder( comboBox, new LineBorder( ORANGE, UIScale.scale( 6 ) ) ); } private void applyCustomComboBoxEditorBorderWithIcon( JComboBox comboBox ) { @@ -152,7 +152,7 @@ public class FlatCustomBordersTest } private void applyCustomComboBoxRendererBorder( JComboBox comboBox ) { - applyCustomComboBoxRendererBorder( comboBox, new LineBorder( ORANGE, UIScale.scale( 3 ) ) ); + applyCustomComboBoxRendererBorder( comboBox, new LineBorder( ORANGE, UIScale.scale( 6 ) ) ); } private void applyCustomComboBoxRendererBorderWithIcon( JComboBox comboBox ) {