diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc1a57c..1050dcf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,36 @@ FlatLaf Change Log ================== -## 1.3-SNAPSHOT +## 1.4-SNAPSHOT + +#### 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. + +#### Fixed bugs + +- 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) +- 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 + components by: + - `2px` at `1.75x` in **Light** and **Dark** themes + - `2px` at `1.25x` and `2.25x` in **IntelliJ** and **Darcula** themes + + +## 1.3 #### New features and improvements @@ -10,13 +39,15 @@ FlatLaf Change Log `PasswordField.focusedBackground`, `FormattedTextField.focusedBackground`, `TextArea.focusedBackground`, `TextPane.focusedBackground`, `EditorPane.focusedBackground`, `ComboBox.focusedBackground`, - `ComboBox.buttonFocusedBackground`, `ComboBox.popupFocusedBackground` and + `ComboBox.buttonFocusedBackground`, `ComboBox.popupBackground` and `Spinner.focusedBackground`). (issue #335) #### Fixed bugs - Fixed white lines at bottom and right side of window (in dark themes on HiDPI screens with scaling enabled). +- ScrollBar: Fixed left/top arrow icon location (if visible). (issue #329) +- Spinner: Fixed up/down arrow icon location. - ToolTip: Fixed positioning of huge tooltips. (issue #333) diff --git a/build.gradle.kts b/build.gradle.kts index d40e897e..4537b107 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,8 +14,8 @@ * limitations under the License. */ -val releaseVersion = "1.2" -val developmentVersion = "1.3-SNAPSHOT" +val releaseVersion = "1.3" +val developmentVersion = "1.4-SNAPSHOT" version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion diff --git a/flatlaf-core/build.gradle.kts b/flatlaf-core/build.gradle.kts index 8ba273ee..97f2fab0 100644 --- a/flatlaf-core/build.gradle.kts +++ b/flatlaf-core/build.gradle.kts @@ -23,6 +23,7 @@ plugins { dependencies { testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" ) + testImplementation( "org.junit.jupiter:junit-jupiter-params" ) testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" ) } 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 52032e36..8f107a42 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -743,6 +743,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/LinuxFontPolicy.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/LinuxFontPolicy.java index b6417f13..b20fba54 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/LinuxFontPolicy.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/LinuxFontPolicy.java @@ -128,7 +128,7 @@ class LinuxFontPolicy // find last word in family int index = family.lastIndexOf( ' ' ); if( index < 0 ) - return createFont( "Dialog", style, size, dsize );; + return createFont( "Dialog", style, size, dsize ); // check whether last work contains some font weight (e.g. Ultra-Bold or Heavy) String lastWord = family.substring( index + 1 ).toLowerCase(); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java index 288ef851..9f59f30d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatArrowButton.java @@ -48,8 +48,8 @@ public class FlatArrowButton protected Color pressedBackground; private int arrowWidth = DEFAULT_ARROW_WIDTH; - private int xOffset = 0; - private int yOffset = 0; + private float xOffset = 0; + private float yOffset = 0; private boolean hover; private boolean pressed; @@ -126,19 +126,19 @@ public class FlatArrowButton return pressed; } - public int getXOffset() { + public float getXOffset() { return xOffset; } - public void setXOffset( int xOffset ) { + public void setXOffset( float xOffset ) { this.xOffset = xOffset; } - public int getYOffset() { + public float getYOffset() { return yOffset; } - public void setYOffset( int yOffset ) { + public void setYOffset( float yOffset ) { this.yOffset = yOffset; } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatBorder.java index 49523483..25dc83cc 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatBorder.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatBorder.java @@ -184,13 +184,14 @@ public class FlatBorder @Override public Insets getBorderInsets( Component c, Insets insets ) { float focusWidth = scale( (float) getFocusWidth( c ) ); - float ow = focusWidth + scale( (float) getLineWidth( c ) ); + int ow = Math.round( focusWidth + scale( (float) getLineWidth( c ) ) ); insets = super.getBorderInsets( c, insets ); - insets.top = Math.round( scale( (float) insets.top ) + ow ); - insets.left = Math.round( scale( (float) insets.left ) + ow ); - insets.bottom = Math.round( scale( (float) insets.bottom ) + ow ); - insets.right = Math.round( scale( (float) insets.right ) + ow ); + + insets.top = scale( insets.top ) + ow; + insets.left = scale( insets.left ) + ow; + insets.bottom = scale( insets.bottom ) + ow; + insets.right = scale( insets.right ) + ow; if( isCellEditor( c ) ) { // remove top and bottom insets if used as cell editor diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java index 4daf92d7..f4134ea3 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java @@ -569,9 +569,9 @@ public class FlatButtonUI prefSize.width = Math.max( prefSize.width, prefSize.height ); } else if( !isIconOnlyOrSingleCharacter && !isToolBarButton( c ) && c.getBorder() instanceof FlatButtonBorder ) { // apply minimum width/height - float focusWidth = FlatUIUtils.getBorderFocusWidth( c ); - prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + Math.round( focusWidth * 2 ) ); - prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + Math.round( focusWidth * 2 ) ); + int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 ); + prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw ); + prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + fw ); } return prefSize; 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/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java index 146c4414..9064a227 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; @@ -39,7 +40,6 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.Rectangle2D; import java.beans.PropertyChangeListener; -import java.lang.ref.WeakReference; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import javax.swing.AbstractAction; @@ -71,7 +71,6 @@ import javax.swing.text.JTextComponent; import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStyleSupport.Styleable; import com.formdev.flatlaf.util.SystemInfo; -import com.formdev.flatlaf.util.UIScale; /** * Provides the Flat LaF UI delegate for {@link javax.swing.JComboBox}. @@ -106,7 +105,7 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault ComboBox.buttonDisabledArrowColor Color * @uiDefault ComboBox.buttonHoverArrowColor Color * @uiDefault ComboBox.buttonPressedArrowColor Color - * @uiDefault ComboBox.popupFocusedBackground Color optional + * @uiDefault ComboBox.popupBackground Color optional * * @author Karl Tauber */ @@ -134,13 +133,14 @@ public class FlatComboBoxUI @Styleable protected Color buttonHoverArrowColor; @Styleable protected Color buttonPressedArrowColor; - @Styleable protected Color popupFocusedBackground; + @Styleable protected Color popupBackground; private MouseListener hoverListener; protected boolean hover; protected boolean pressed; - private WeakReference lastRendererComponent; + private CellPaddingBorder paddingBorder; + private Map oldStyleValues; private AtomicBoolean borderShared; @@ -227,15 +227,14 @@ public class FlatComboBoxUI buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" ); buttonPressedArrowColor = UIManager.getColor( "ComboBox.buttonPressedArrowColor" ); - popupFocusedBackground = UIManager.getColor( "ComboBox.popupFocusedBackground" ); + popupBackground = UIManager.getColor( "ComboBox.popupBackground" ); // set maximumRowCount int maximumRowCount = UIManager.getInt( "ComboBox.maximumRowCount" ); if( maximumRowCount > 0 && maximumRowCount != 8 && comboBox.getMaximumRowCount() == 8 ) comboBox.setMaximumRowCount( maximumRowCount ); - // scale - padding = UIScale.scale( padding ); + paddingBorder = new CellPaddingBorder( padding ); MigLayoutVisualPadding.install( comboBox ); } @@ -260,7 +259,9 @@ public class FlatComboBoxUI buttonHoverArrowColor = null; buttonPressedArrowColor = null; - popupFocusedBackground = null; + popupBackground = null; + + paddingBorder.uninstall(); oldStyleValues = null; borderShared = null; @@ -291,11 +292,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 ) ); - } } }; } @@ -381,9 +377,13 @@ 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() ); + } // explicitly make non-opaque if( editor instanceof JComponent ) @@ -391,6 +391,7 @@ public class FlatComboBoxUI editor.applyComponentOrientation( comboBox.getComponentOrientation() ); + updateEditorPadding(); updateEditorColors(); // macOS @@ -407,6 +408,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 @@ -516,30 +536,24 @@ public class FlatComboBoxUI @Override @SuppressWarnings( "unchecked" ) public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) { + paddingBorder.uninstall(); + ListCellRenderer renderer = comboBox.getRenderer(); - uninstallCellPaddingBorder( renderer ); if( renderer == null ) renderer = new DefaultListCellRenderer(); Component c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false ); c.setFont( comboBox.getFont() ); c.applyComponentOrientation( comboBox.getComponentOrientation() ); - uninstallCellPaddingBorder( c ); boolean enabled = comboBox.isEnabled(); c.setBackground( getBackground( enabled ) ); 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 @@ -571,77 +585,50 @@ public class FlatComboBoxUI @Override public Dimension getMinimumSize( JComponent c ) { Dimension minimumSize = super.getMinimumSize( c ); - minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) ); + int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 ); + minimumSize.width = Math.max( minimumSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw ); return minimumSize; } @Override protected Dimension getDefaultSize() { - @SuppressWarnings( "unchecked" ) - ListCellRenderer renderer = comboBox.getRenderer(); - uninstallCellPaddingBorder( renderer ); - + paddingBorder.uninstall(); Dimension size = super.getDefaultSize(); - - uninstallCellPaddingBorder( renderer ); + paddingBorder.uninstall(); return size; } @Override protected Dimension getDisplaySize() { - @SuppressWarnings( "unchecked" ) - ListCellRenderer renderer = comboBox.getRenderer(); - uninstallCellPaddingBorder( renderer ); + 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 ); } - uninstallCellPaddingBorder( renderer ); - 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 void uninstallCellPaddingBorder( Object o ) { - CellPaddingBorder.uninstall( o ); - if( lastRendererComponent != null ) { - CellPaddingBorder.uninstall( lastRendererComponent ); - lastRendererComponent = null; - } - } - private boolean isCellRenderer() { return comboBox.getParent() instanceof CellRendererPane; } @@ -652,6 +639,9 @@ public class FlatComboBoxUI return parentParent != null && !comboBox.getBackground().equals( parentParent.getBackground() ); } + /** + * @since 1.3 + */ public static boolean isPermanentFocusOwner( JComboBox comboBox ) { if( comboBox.isEditable() ) { Component editorComponent = comboBox.getEditor().getEditorComponent(); @@ -707,13 +697,11 @@ public class FlatComboBoxUI protected class FlatComboPopup extends BasicComboPopup { - private CellPaddingBorder paddingBorder; - protected FlatComboPopup( JComboBox combo ) { 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(); @@ -781,8 +769,8 @@ public class FlatComboBoxUI } void updateStyle() { - if( popupFocusedBackground != null ) - list.setBackground( popupFocusedBackground ); + if( popupBackground != null ) + list.setBackground( popupBackground ); } @Override @@ -796,6 +784,19 @@ public class FlatComboBoxUI }; } + @Override + protected int getPopupHeightForRowCount( int maxRowCount ) { + int height = super.getPopupHeightForRowCount( maxRowCount ); + paddingBorder.uninstall(); + return height; + } + + @Override + protected void paintChildren( Graphics g ) { + super.paintChildren( g ); + paddingBorder.uninstall(); + } + //---- class PopupListCellRenderer ----- private class PopupListCellRenderer @@ -805,22 +806,15 @@ public class FlatComboBoxUI public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus ) { - ListCellRenderer renderer = comboBox.getRenderer(); - CellPaddingBorder.uninstall( renderer ); - CellPaddingBorder.uninstall( lastRendererComponent ); + paddingBorder.uninstall(); + ListCellRenderer renderer = comboBox.getRenderer(); if( renderer == null ) renderer = new DefaultListCellRenderer(); Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus ); c.applyComponentOrientation( comboBox.getComponentOrientation() ); - if( c instanceof JComponent ) { - if( paddingBorder == null ) - paddingBorder = new CellPaddingBorder( padding ); - paddingBorder.install( (JComponent) c ); - } - - lastRendererComponent = (c != renderer) ? new WeakReference<>( c ) : null; + paddingBorder.install( c ); return c; } @@ -830,49 +824,63 @@ 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. - * - * The renderer border is painted on the outside of this border. + *

+ * The renderer border is painted on the outer side of this border. */ private static class CellPaddingBorder extends AbstractBorder { private final Insets padding; + private JComponent rendererComponent; private Border rendererBorder; CellPaddingBorder( Insets padding ) { this.padding = padding; } - void install( JComponent rendererComponent ) { - Border oldBorder = rendererComponent.getBorder(); - if( !(oldBorder instanceof CellPaddingBorder) ) { - rendererBorder = oldBorder; - rendererComponent.setBorder( this ); - } - } - - static void uninstall( Object o ) { - if( o instanceof WeakReference ) - o = ((WeakReference)o).get(); - - if( !(o instanceof JComponent) ) + void install( Component c ) { + if( !(c instanceof JComponent) ) return; - JComponent rendererComponent = (JComponent) o; - Border border = rendererComponent.getBorder(); - if( border instanceof CellPaddingBorder ) { - CellPaddingBorder paddingBorder = (CellPaddingBorder) border; - rendererComponent.setBorder( paddingBorder.rendererBorder ); - paddingBorder.rendererBorder = null; - } + JComponent jc = (JComponent) c; + Border oldBorder = jc.getBorder(); + if( oldBorder == this ) + return; // already installed + + // this border can be installed only at one component + uninstall(); + + // remember component where this border was installed for uninstall + rendererComponent = jc; + + // remember old border and replace it + rendererBorder = oldBorder; + rendererComponent.setBorder( this ); + } + + /** + * Uninstall border from previously installed component. + * Because this border is installed in PopupListCellRenderer.getListCellRendererComponent(), + * there is no single place to uninstall it. + * This is the reason why this method is called from various places. + */ + void uninstall() { + if( rendererComponent == null ) + return; + + if( rendererComponent.getBorder() == this ) + rendererComponent.setBorder( rendererBorder ); + rendererComponent = null; + rendererBorder = null; } @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/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatFormattedTextFieldUI.java index 11d91245..a016d7da 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 @@ -39,8 +39,6 @@ import javax.swing.plaf.ComponentUI; * * * - * @uiDefault TextComponent.arc int - * @uiDefault Component.focusWidth int * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean * @uiDefault FormattedTextField.placeholderForeground Color 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 d81c267a..f14cf1f7 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 @@ -16,34 +16,32 @@ package com.formdev.flatlaf.ui; -import java.awt.Color; -import java.awt.Dimension; import java.awt.Graphics; -import java.awt.Graphics2D; +import java.awt.Shape; import java.awt.Toolkit; -import java.awt.event.FocusListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import java.beans.PropertyChangeEvent; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.Action; +import javax.swing.ActionMap; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.basic.BasicPasswordFieldUI; -import javax.swing.text.Caret; +import javax.swing.text.DefaultEditorKit; +import javax.swing.text.Element; import javax.swing.text.JTextComponent; +import javax.swing.text.PasswordView; +import javax.swing.text.View; import com.formdev.flatlaf.icons.FlatCapsLockIcon; import com.formdev.flatlaf.ui.FlatStyleSupport.Styleable; -import com.formdev.flatlaf.util.HiDPIUtils; /** * Provides the Flat LaF UI delegate for {@link javax.swing.JPasswordField}. * - * + * * * @uiDefault PasswordField.font Font * @uiDefault PasswordField.background Color @@ -56,42 +54,32 @@ import com.formdev.flatlaf.util.HiDPIUtils; * @uiDefault PasswordField.inactiveForeground Color used if not enabled (yes, this is confusing; this should be named disabledForeground) * @uiDefault PasswordField.border Border * @uiDefault PasswordField.margin Insets - * @uiDefault PasswordField.echoChar character * @uiDefault PasswordField.caretBlinkRate int default is 500 milliseconds * - * + * * * @uiDefault Component.minimumWidth int * @uiDefault Component.isIntelliJTheme boolean * @uiDefault PasswordField.placeholderForeground Color * @uiDefault PasswordField.focusedBackground Color optional - * @uiDefault PasswordField.showCapsLock boolean - * @uiDefault PasswordField.capsLockIcon Icon * @uiDefault TextComponent.selectAllOnFocusPolicy String never, once (default) or always * @uiDefault TextComponent.selectAllOnMouseClick boolean * + * + * + * @uiDefault PasswordField.echoChar character + * @uiDefault PasswordField.showCapsLock boolean + * @uiDefault PasswordField.capsLockIcon Icon + * * @author Karl Tauber */ public class FlatPasswordFieldUI - extends BasicPasswordFieldUI + extends FlatTextFieldUI { - @Styleable protected int minimumWidth; - protected boolean isIntelliJTheme; - private Color background; - @Styleable protected Color disabledBackground; - @Styleable protected Color inactiveBackground; - @Styleable protected Color placeholderForeground; - @Styleable protected Color focusedBackground; @Styleable protected boolean showCapsLock; protected Icon capsLockIcon; - private Color oldDisabledBackground; - private Color oldInactiveBackground; - - private FocusListener focusListener; private KeyListener capsLockListener; - private Map oldStyleValues; - private AtomicBoolean borderShared; private boolean capsLockIconShared = true; public static ComponentUI createUI( JComponent c ) { @@ -99,10 +87,8 @@ public class FlatPasswordFieldUI } @Override - public void installUI( JComponent c ) { - super.installUI( c ); - - applyStyle( FlatStyleSupport.getStyle( c ) ); + protected String getPropertyPrefix() { + return "PasswordField"; } @Override @@ -110,48 +96,25 @@ public class FlatPasswordFieldUI super.installDefaults(); String prefix = getPropertyPrefix(); - minimumWidth = UIManager.getInt( "Component.minimumWidth" ); - isIntelliJTheme = UIManager.getBoolean( "Component.isIntelliJTheme" ); - background = UIManager.getColor( prefix + ".background" ); - disabledBackground = UIManager.getColor( prefix + ".disabledBackground" ); - inactiveBackground = UIManager.getColor( prefix + ".inactiveBackground" ); - placeholderForeground = UIManager.getColor( prefix + ".placeholderForeground" ); - focusedBackground = UIManager.getColor( prefix + ".focusedBackground" ); + Character echoChar = (Character) UIManager.get( prefix + ".echoChar" ); + if( echoChar != null ) + LookAndFeel.installProperty( getComponent(), "echoChar", echoChar ); + showCapsLock = UIManager.getBoolean( "PasswordField.showCapsLock" ); capsLockIcon = UIManager.getIcon( "PasswordField.capsLockIcon" ); - - LookAndFeel.installProperty( getComponent(), "opaque", false ); - - MigLayoutVisualPadding.install( getComponent() ); } @Override protected void uninstallDefaults() { super.uninstallDefaults(); - background = null; - disabledBackground = null; - inactiveBackground = null; - placeholderForeground = null; - focusedBackground = null; capsLockIcon = null; - - oldDisabledBackground = null; - oldInactiveBackground = null; - - oldStyleValues = null; - borderShared = null; - - MigLayoutVisualPadding.uninstall( getComponent() ); } @Override protected void installListeners() { super.installListeners(); - // necessary to update focus border and background - focusListener = new FlatUIUtils.RepaintFocusListener( getComponent(), null ); - // update caps lock indicator capsLockListener = new KeyAdapter() { @Override @@ -168,7 +131,6 @@ public class FlatPasswordFieldUI } }; - getComponent().addFocusListener( focusListener ); getComponent().addKeyListener( capsLockListener ); } @@ -176,43 +138,24 @@ public class FlatPasswordFieldUI protected void uninstallListeners() { super.uninstallListeners(); - getComponent().removeFocusListener( focusListener ); getComponent().removeKeyListener( capsLockListener ); - focusListener = null; capsLockListener = null; } @Override - protected Caret createCaret() { - return new FlatCaret( UIManager.getString( "TextComponent.selectAllOnFocusPolicy" ), - UIManager.getBoolean( "TextComponent.selectAllOnMouseClick" ) ); + protected void installKeyboardActions() { + super.installKeyboardActions(); + + // map "select-word" action (double-click) to "select-line" action + ActionMap map = SwingUtilities.getUIActionMap( getComponent() ); + if( map != null && map.get( DefaultEditorKit.selectWordAction ) != null ) { + Action selectLineAction = map.get( DefaultEditorKit.selectLineAction ); + if( selectLineAction != null ) + map.put( DefaultEditorKit.selectWordAction, selectLineAction ); + } } @Override - protected void propertyChange( PropertyChangeEvent e ) { - String propertyName = e.getPropertyName(); - if( "editable".equals( propertyName ) || "enabled".equals( propertyName ) ) - updateBackground(); - else - super.propertyChange( e ); - FlatTextFieldUI.propertyChange( getComponent(), e, this::applyStyle ); - } - - /** - * @since TODO - */ - protected void applyStyle( Object style ) { - oldDisabledBackground = disabledBackground; - oldInactiveBackground = inactiveBackground; - - oldStyleValues = FlatStyleSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); - - updateBackground(); - } - - /** - * @since TODO - */ protected Object applyStyleProperty( String key, Object value ) { if( key.equals( "capsLockIconColor" ) && capsLockIcon instanceof FlatCapsLockIcon ) { if( capsLockIconShared ) { @@ -222,24 +165,23 @@ public class FlatPasswordFieldUI return ((FlatCapsLockIcon)capsLockIcon).applyStyleProperty( key, value ); } - if( borderShared == null ) - borderShared = new AtomicBoolean( true ); - return FlatStyleSupport.applyToAnnotatedObjectOrBorder( this, key, value, getComponent(), borderShared ); + return super.applyStyleProperty( key, value ); } - private void updateBackground() { - FlatTextFieldUI.updateBackground( getComponent(), background, - disabledBackground, inactiveBackground, - oldDisabledBackground, oldInactiveBackground ); + @Override + public View create( Element elem ) { + return new PasswordView( elem ); } @Override protected void paintSafely( Graphics g ) { - FlatTextFieldUI.paintBackground( g, getComponent(), isIntelliJTheme, focusedBackground ); - FlatTextFieldUI.paintPlaceholder( g, getComponent(), placeholderForeground ); - paintCapsLock( 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 ); - super.paintSafely( HiDPIUtils.createGraphicsTextYCorrection( (Graphics2D) g ) ); + paintCapsLock( g ); } protected void paintCapsLock( Graphics g ) { @@ -255,19 +197,4 @@ public class FlatPasswordFieldUI int x = c.getWidth() - capsLockIcon.getIconWidth() - y; capsLockIcon.paintIcon( c, g, x, y ); } - - @Override - protected void paintBackground( Graphics g ) { - // background is painted elsewhere - } - - @Override - public Dimension getPreferredSize( JComponent c ) { - return FlatTextFieldUI.applyMinimumWidth( c, super.getPreferredSize( c ), minimumWidth ); - } - - @Override - public Dimension getMinimumSize( JComponent c ) { - return FlatTextFieldUI.applyMinimumWidth( c, super.getMinimumSize( c ), minimumWidth ); - } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java index 38627b54..bd406d4a 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollPaneUI.java @@ -369,6 +369,9 @@ public class FlatScrollPaneUI paint( g, c ); } + /** + * @since 1.3 + */ public static boolean isPermanentFocusOwner( JScrollPane scrollPane ) { JViewport viewport = scrollPane.getViewport(); Component view = (viewport != null) ? viewport.getView() : null; 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 c230a82f..c37691fc 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 @@ -214,6 +214,7 @@ public class FlatSpinnerUI if( textField != null ) textField.setOpaque( false ); + updateEditorPadding(); updateEditorColors(); return editor; } @@ -224,6 +225,8 @@ public class FlatSpinnerUI removeEditorFocusListener( oldEditor ); addEditorFocusListener( newEditor ); + + updateEditorPadding(); updateEditorColors(); } @@ -239,6 +242,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 ) { @@ -256,6 +265,9 @@ public class FlatSpinnerUI : null; } + /** + * @since 1.3 + */ public static boolean isPermanentFocusOwner( JSpinner spinner ) { if( FlatUIUtils.isPermanentFocusOwner( spinner ) ) return true; @@ -306,7 +318,7 @@ public class FlatSpinnerUI FlatArrowButton button = new FlatArrowButton( direction, arrowType, buttonArrowColor, buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null ); button.setName( name ); - button.setYOffset( (direction == SwingConstants.NORTH) ? 1 : -1 ); + button.setYOffset( (direction == SwingConstants.NORTH) ? 1.25f : -1.25f ); if( direction == SwingConstants.NORTH ) installNextButtonListeners( button ); else @@ -435,7 +447,7 @@ public class FlatSpinnerUI if( nextButton == null && previousButton == null ) { if( editor != null ) - editor.setBounds( FlatUIUtils.subtractInsets( r, padding ) ); + editor.setBounds( r ); return; } @@ -455,7 +467,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-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java index fce393f2..8f7e47ff 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 java.util.Map; @@ -44,6 +45,7 @@ import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStyleSupport.Styleable; 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}. @@ -177,6 +179,7 @@ public class FlatTextFieldUI switch( e.getPropertyName() ) { case FlatClientProperties.PLACEHOLDER_TEXT: case FlatClientProperties.COMPONENT_ROUND_RECT: + case FlatClientProperties.TEXT_FIELD_PADDING: c.repaint(); break; @@ -294,14 +297,14 @@ public class FlatTextFieldUI if( !(background instanceof UIResource) ) return background; + // focused + if( focusedBackground != null && FlatUIUtils.isPermanentFocusOwner( c ) ) + return focusedBackground; + // for compatibility with IntelliJ themes if( isIntelliJTheme && (!c.isEnabled() || !c.isEditable()) ) return FlatUIUtils.getParentBackground( c ); - // focused and editable - if( focusedBackground != null && c.isEditable() && FlatUIUtils.isPermanentFocusOwner( c ) ) - return focusedBackground; - return background; } @@ -359,4 +362,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-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java index 4e3cf598..39a22ebe 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java @@ -660,7 +660,7 @@ public class FlatUIUtils * @since 1.1 */ public static void paintArrow( Graphics2D g, int x, int y, int width, int height, - int direction, boolean chevron, int arrowSize, int xOffset, int yOffset ) + int direction, boolean chevron, int arrowSize, float xOffset, float yOffset ) { // compute arrow width/height int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) ); @@ -679,8 +679,10 @@ public class FlatUIUtils int extra = chevron ? 1 : 0; // compute arrow location - int ax = x + Math.round( ((width - (aw + extra)) / 2f) + UIScale.scale( (float) xOffset ) ); - int ay = y + Math.round( ((height - (ah + extra)) / 2f) + UIScale.scale( (float) yOffset ) ); + float ox = ((width - (aw + extra)) / 2f) + UIScale.scale( xOffset ); + float oy = ((height - (ah + extra)) / 2f) + UIScale.scale( yOffset ); + int ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -ox ) : Math.round( ox )); + int ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -oy ) : Math.round( oy )); // paint arrow g.translate( ax, ay ); diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/FlatStylingTests.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/FlatStylingTests.java index 58645e39..687ffa2e 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/FlatStylingTests.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/FlatStylingTests.java @@ -164,7 +164,7 @@ public class FlatStylingTests ui.applyStyle( "buttonHoverArrowColor: #fff" ); ui.applyStyle( "buttonPressedArrowColor: #fff" ); - ui.applyStyle( "popupFocusedBackground: #fff" ); + ui.applyStyle( "popupBackground: #fff" ); // border flatRoundBorder( style -> ui.applyStyle( style ) ); 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 new file mode 100644 index 00000000..02f559a8 --- /dev/null +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatComponentSizes.java @@ -0,0 +1,203 @@ +/* + * 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.ui; + +import static org.junit.jupiter.api.Assertions.assertEquals; +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.Border; +import javax.swing.border.LineBorder; +import javax.swing.plaf.basic.BasicComboBoxEditor; +import javax.swing.plaf.basic.BasicComboBoxRenderer; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import com.formdev.flatlaf.util.UIScale; + +/** + * @author Karl Tauber + */ +public class TestFlatComponentSizes +{ + @BeforeAll + static void setup() { + TestUtils.setup( false ); + } + + @AfterAll + static void cleanup() { + TestUtils.cleanup(); + } + + static float[] factors() { + return TestUtils.FACTORS; + } + + @ParameterizedTest + @MethodSource( "factors" ) + void sizes( float factor ) { + TestUtils.scaleFont( factor ); + + + // should have same default size (minimumWidth is 64) + JTextField textField = new JTextField(); + JFormattedTextField formattedTextField = new JFormattedTextField(); + JPasswordField passwordField = new JPasswordField(); + JSpinner spinner = new JSpinner(); + + Dimension textFieldSize = textField.getPreferredSize(); + assertEquals( textFieldSize, formattedTextField.getPreferredSize() ); + assertEquals( textFieldSize, passwordField.getPreferredSize() ); + assertEquals( textFieldSize, spinner.getPreferredSize() ); + + + // should have same default size (minimumWidth is 72) + JButton button = new JButton( "text" ); + JComboBox comboBox = new JComboBox<>(); + JComboBox comboBoxEditable = new JComboBox<>(); + comboBoxEditable.setEditable( true ); + + Dimension buttonSize = button.getPreferredSize(); + assertEquals( buttonSize, comboBox.getPreferredSize() ); + assertEquals( buttonSize, comboBoxEditable.getPreferredSize() ); + + + // should have same height + JToggleButton toggleButton = new JToggleButton( "text" ); + + assertEquals( textFieldSize.height, button.getPreferredSize().height ); + assertEquals( textFieldSize.height, toggleButton.getPreferredSize().height ); + + + // should have same size + JCheckBox checkBox = new JCheckBox( "text" ); + JRadioButton radioButton = new JRadioButton( "text" ); + assertEquals( checkBox.getPreferredSize(), radioButton.getPreferredSize() ); + + + // should have same size + JMenu menu = new JMenu( "text" ); + JMenuItem menuItem = new JMenuItem( "text" ); + JCheckBoxMenuItem checkBoxMenuItem = new JCheckBoxMenuItem( "text" ); + JRadioButtonMenuItem radioButtonMenuItem = new JRadioButtonMenuItem( "text" ); + + Dimension menuSize = menu.getPreferredSize(); + assertEquals( menuSize, menuItem.getPreferredSize() ); + assertEquals( menuSize, checkBoxMenuItem.getPreferredSize() ); + assertEquals( menuSize, radioButtonMenuItem.getPreferredSize() ); + + + TestUtils.resetFont(); + } + + @ParameterizedTest + @MethodSource( "factors" ) + void comboBox( float factor ) { + TestUtils.scaleFont( factor ); + + String[] items = { "t" }; + 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( 6 ) ) ); + applyCustomComboBoxRendererBorder( comboBox3, new BorderWithIcon() ); + applyCustomComboBoxRendererBorder( comboBox4, null ); + + Dimension size = comboBox.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() ); + + TestUtils.resetFont(); + } + + @SuppressWarnings( "unchecked" ) + private void applyCustomComboBoxRendererBorder( JComboBox comboBox, Border border ) { + BasicComboBoxRenderer customRenderer = new BasicComboBoxRenderer(); + customRenderer.setBorder( border ); + comboBox.setRenderer( customRenderer ); + } + + @ParameterizedTest + @MethodSource( "factors" ) + void comboBoxEditable( float factor ) { + TestUtils.scaleFont( factor ); + + String[] items = { "t" }; + 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( 6 ) ) ); + applyCustomComboBoxEditorBorder( comboBox3, new BorderWithIcon() ); + applyCustomComboBoxEditorBorder( comboBox4, null ); + + Dimension size = comboBox.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() ); + + TestUtils.resetFont(); + } + + private void applyCustomComboBoxEditorBorder( JComboBox comboBox, Border border ) { + JTextField customTextField = new JTextField(); + if( border != null ) + customTextField.setBorder( border ); + comboBox.setEditor( new BasicComboBoxEditor() { + @Override + protected JTextField createEditorComponent() { + return customTextField; + } + } ); + } + + //---- class BorderWithIcon ----------------------------------------------- + + private static class BorderWithIcon + implements Border + { + @Override + public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { + } + + @Override + public boolean isBorderOpaque() { + return false; + } + + @Override + public Insets getBorderInsets( Component c ) { + return new Insets( 0, 0, 0, UIScale.scale( 16 ) + 4 ); + } + } +} diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatComponentSizesWithFocus.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatComponentSizesWithFocus.java new file mode 100644 index 00000000..074cacd7 --- /dev/null +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatComponentSizesWithFocus.java @@ -0,0 +1,31 @@ +/* + * 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.ui; + +import org.junit.jupiter.api.BeforeAll; + +/** + * @author Karl Tauber + */ +public class TestFlatComponentSizesWithFocus + extends TestFlatComponentSizes +{ + @BeforeAll + static void setup() { + TestUtils.setup( true ); + } +} diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestUtils.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestUtils.java new file mode 100644 index 00000000..e4bead06 --- /dev/null +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestUtils.java @@ -0,0 +1,53 @@ +/* + * 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.ui; + +import java.awt.Font; +import javax.swing.UIManager; +import com.formdev.flatlaf.FlatIntelliJLaf; +import com.formdev.flatlaf.FlatLightLaf; +import com.formdev.flatlaf.FlatSystemProperties; + +/** + * @author Karl Tauber + */ +public class TestUtils +{ + public static final float[] FACTORS = new float[] { 1f, 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 2.75f, 3f, 3.25f, 3.5f, 3.75f, 4f, 5f, 6f }; + + public static void setup( boolean withFocus ) { + System.setProperty( FlatSystemProperties.UI_SCALE, "1x" ); + if( withFocus ) + FlatIntelliJLaf.setup(); + else + FlatLightLaf.setup(); + System.clearProperty( FlatSystemProperties.UI_SCALE ); + } + + public static void cleanup() { + UIManager.put( "defaultFont", null ); + } + + public static void scaleFont( float factor ) { + Font defaultFont = UIManager.getLookAndFeelDefaults().getFont( "defaultFont" ); + UIManager.put( "defaultFont", defaultFont.deriveFont( (float) Math.round( defaultFont.getSize() * factor ) ) ); + } + + public static void resetFont() { + UIManager.put( "defaultFont", null ); + } +} diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatInspector.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatInspector.java index 8bd74b3a..48b3f3ef 100644 --- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatInspector.java +++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatInspector.java @@ -44,6 +44,7 @@ import java.awt.event.WindowListener; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.lang.reflect.Field; +import java.lang.reflect.Method; import javax.swing.AbstractButton; import javax.swing.JComponent; import javax.swing.JLayeredPane; @@ -64,6 +65,7 @@ import javax.swing.plaf.UIResource; import javax.swing.text.JTextComponent; import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatUIUtils; +import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.UIScale; /** @@ -478,9 +480,17 @@ public class FlatInspector if( c instanceof JComponent ) { try { - Field f = JComponent.class.getDeclaredField( "ui" ); - f.setAccessible( true ); - Object ui = f.get( c ); + Object ui; + if( SystemInfo.isJava_9_orLater ) { + // Java 9+: use public method JComponent.getUI() + Method m = JComponent.class.getMethod( "getUI" ); + ui = m.invoke( c ); + } else { + // Java 8: read protected field 'ui' + Field f = JComponent.class.getDeclaredField( "ui" ); + f.setAccessible( true ); + ui = f.get( c ); + } appendRow( buf, "UI", (ui != null ? toString( ui.getClass(), classHierarchy ) : "null") ); } catch( Exception ex ) { // ignore @@ -553,6 +563,9 @@ public class FlatInspector String simpleName = (dot >= 0) ? name.substring( dot + 1 ) : name; buf.append( simpleName ).append( ' ' ).append( toDimmedText( "(" + pkg + ")" ) ); + if( UIResource.class.isAssignableFrom( cls ) ) + buf.append( " UI" ); + if( !classHierarchy ) break; @@ -613,11 +626,14 @@ public class FlatInspector String s = toString( b.getClass(), classHierarchy ); - if( b instanceof EmptyBorder ) - s += '(' + toString( ((EmptyBorder)b).getBorderInsets() ) + ')'; - - if( b instanceof UIResource ) - s += " UI"; + if( b instanceof EmptyBorder ) { + String borderInsets = " (" + toString( ((EmptyBorder)b).getBorderInsets() ) + ')'; + int brIndex = s.indexOf( "
" ); + if( brIndex >= 0 ) + s = s.substring( 0, brIndex ) + borderInsets + s.substring( brIndex ); + else + s += borderInsets; + } return s; } diff --git a/flatlaf-jide-oss/build.gradle.kts b/flatlaf-jide-oss/build.gradle.kts index a78027f3..397d8c7a 100644 --- a/flatlaf-jide-oss/build.gradle.kts +++ b/flatlaf-jide-oss/build.gradle.kts @@ -23,7 +23,7 @@ dependencies { implementation( project( ":flatlaf-core" ) ) // use compileOnly() because there are various JIDE libraries available on Maven Central - compileOnly( "com.formdev:jide-oss:3.7.11.1" ) + compileOnly( "com.formdev:jide-oss:3.7.12" ) } java { diff --git a/flatlaf-testing/build.gradle.kts b/flatlaf-testing/build.gradle.kts index 953491c8..53b51367 100644 --- a/flatlaf-testing/build.gradle.kts +++ b/flatlaf-testing/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { implementation( "com.jgoodies:jgoodies-forms:1.9.0" ) implementation( "org.swinglabs.swingx:swingx-all:1.6.5-1" ) implementation( "org.swinglabs.swingx:swingx-beaninfo:1.6.5-1" ) - implementation( "com.formdev:jide-oss:3.7.11.1" ) + implementation( "com.formdev:jide-oss:3.7.12" ) implementation( "com.glazedlists:glazedlists:1.11.0" ) implementation( "org.netbeans.api:org-openide-awt:RELEASE112" ) } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.java index 0bf90add..160caca6 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.java @@ -147,7 +147,7 @@ public class FlatAnimatedIconTest @Override public void paintIconAnimated( Component c, Graphics g, int x, int y, float animatedValue ) { - Color color = ColorFunctions.mix( onColor, offColor, animatedValue );; + Color color = ColorFunctions.mix( onColor, offColor, animatedValue ); // border g.setColor( color ); @@ -190,7 +190,7 @@ public class FlatAnimatedIconTest @Override public void paintIconAnimated( Component c, Graphics g, int x, int y, float animatedValue ) { - Color color = ColorFunctions.mix( onColor, offColor, animatedValue );; + Color color = ColorFunctions.mix( onColor, offColor, animatedValue ); g.setColor( color ); g.fillRoundRect( x, y, width, height, height, height ); diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatBaselineTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatBaselineTest.java index 22a4851c..028a8eea 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatBaselineTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatBaselineTest.java @@ -51,6 +51,7 @@ public class FlatBaselineTest JFormattedTextField formattedTextField1 = new JFormattedTextField(); JPasswordField passwordField1 = new JPasswordField(); JComboBox comboBox1 = new JComboBox<>(); + JComboBox comboBox2 = new JComboBox<>(); JSpinner spinner1 = new JSpinner(); JLabel label6 = new JLabel(); JScrollPane scrollPane1 = new JScrollPane(); @@ -88,7 +89,7 @@ public class FlatBaselineTest //======== this ======== setLayout(new MigLayout( - "insets dialog,hidemode 3,debug", + "insets dialog,hidemode 3", // columns "[fill]" + "[fill]" + @@ -96,6 +97,7 @@ public class FlatBaselineTest "[fill]" + "[fill]" + "[fill]" + + "[fill]" + "[fill]", // rows "[]" + @@ -130,7 +132,7 @@ public class FlatBaselineTest //---- textField4 ---- textField4.setText("Dext field"); - add(textField4, "cell 6 0"); + add(textField4, "cell 7 0"); //---- label2 ---- label2.setText("Dext"); @@ -147,8 +149,20 @@ public class FlatBaselineTest //---- passwordField1 ---- passwordField1.setText("Dext"); add(passwordField1, "cell 3 1"); + + //---- comboBox1 ---- + comboBox1.setModel(new DefaultComboBoxModel<>(new String[] { + "Dext" + })); add(comboBox1, "cell 4 1"); - add(spinner1, "cell 5 1"); + + //---- comboBox2 ---- + comboBox2.setModel(new DefaultComboBoxModel<>(new String[] { + "Dext" + })); + comboBox2.setEditable(true); + add(comboBox2, "cell 5 1"); + add(spinner1, "cell 6 1"); //---- label6 ---- label6.setText("Dext"); @@ -171,7 +185,7 @@ public class FlatBaselineTest //---- textField2 ---- textField2.setText("Dext field"); - add(textField2, "cell 6 2"); + add(textField2, "cell 7 2"); //---- label7 ---- label7.setText("Dext"); @@ -230,18 +244,18 @@ public class FlatBaselineTest //---- textField3 ---- textField3.setText("Dext field"); - add(textField3, "cell 6 3"); + add(textField3, "cell 7 3"); //---- label3 ---- label3.setText("Dext"); add(label3, "cell 0 4"); - add(slider1, "cell 1 4 6 1"); + add(slider1, "cell 1 4 7 1"); //---- slider6 ---- slider6.setPaintTicks(true); slider6.setMajorTickSpacing(25); slider6.setMinorTickSpacing(5); - add(slider6, "cell 1 4 6 1"); + add(slider6, "cell 1 4 7 1"); //---- label8 ---- label8.setText("Dext"); @@ -251,14 +265,14 @@ public class FlatBaselineTest slider7.setPaintLabels(true); slider7.setMajorTickSpacing(25); slider7.setMinorTickSpacing(5); - add(slider7, "cell 1 5 6 1"); + add(slider7, "cell 1 5 7 1"); //---- slider8 ---- slider8.setPaintLabels(true); slider8.setPaintTicks(true); slider8.setMajorTickSpacing(25); slider8.setMinorTickSpacing(5); - add(slider8, "cell 1 5 6 1"); + add(slider8, "cell 1 5 7 1"); //---- label4 ---- label4.setText("Dext"); @@ -266,13 +280,13 @@ public class FlatBaselineTest //---- progressBar1 ---- progressBar1.setValue(30); - add(progressBar1, "cell 1 6 6 1"); + add(progressBar1, "cell 1 6 7 1"); //---- progressBar3 ---- progressBar3.setStringPainted(true); progressBar3.setValue(30); - add(progressBar3, "cell 1 6 6 1"); - add(separator1, "cell 1 6 6 1"); + add(progressBar3, "cell 1 6 7 1"); + add(separator1, "cell 1 6 7 1"); //---- label5 ---- label5.setText("Dext"); @@ -280,26 +294,26 @@ public class FlatBaselineTest //---- slider2 ---- slider2.setOrientation(SwingConstants.VERTICAL); - add(slider2, "cell 1 7 6 1"); + add(slider2, "cell 1 7 7 1"); //---- slider3 ---- slider3.setOrientation(SwingConstants.VERTICAL); slider3.setPaintTicks(true); slider3.setMajorTickSpacing(25); slider3.setMinorTickSpacing(5); - add(slider3, "cell 1 7 6 1"); + add(slider3, "cell 1 7 7 1"); //---- progressBar2 ---- progressBar2.setOrientation(SwingConstants.VERTICAL); progressBar2.setValue(30); - add(progressBar2, "cell 1 7 6 1"); + add(progressBar2, "cell 1 7 7 1"); //---- progressBar4 ---- progressBar4.setOrientation(SwingConstants.VERTICAL); progressBar4.setStringPainted(true); progressBar4.setValue(30); - add(progressBar4, "cell 1 7 6 1"); - add(hSpacer1, "cell 1 7 6 1,growx"); + add(progressBar4, "cell 1 7 7 1"); + add(hSpacer1, "cell 1 7 7 1,growx"); //---- label9 ---- label9.setText("Dext"); @@ -310,7 +324,7 @@ public class FlatBaselineTest slider4.setPaintLabels(true); slider4.setMajorTickSpacing(25); slider4.setMinorTickSpacing(5); - add(slider4, "cell 1 8 6 1"); + add(slider4, "cell 1 8 7 1"); //---- slider5 ---- slider5.setOrientation(SwingConstants.VERTICAL); @@ -318,8 +332,8 @@ public class FlatBaselineTest slider5.setPaintTicks(true); slider5.setMajorTickSpacing(25); slider5.setMinorTickSpacing(5); - add(slider5, "cell 1 8 6 1"); - add(hSpacer2, "cell 1 8 6 1,growx"); + add(slider5, "cell 1 8 7 1"); + add(hSpacer2, "cell 1 8 7 1,growx"); // JFormDesigner - End of component initialization //GEN-END:initComponents } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatBaselineTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatBaselineTest.jfd index b41f8d16..21df15b5 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatBaselineTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatBaselineTest.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" @@ -7,8 +7,8 @@ new FormModel { "JavaCodeGenerator.defaultVariableLocal": true } add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { - "$layoutConstraints": "insets dialog,hidemode 3,debug" - "$columnConstraints": "[fill][fill][fill][fill][fill][fill][fill]" + "$layoutConstraints": "insets dialog,hidemode 3" + "$columnConstraints": "[fill][fill][fill][fill][fill][fill][fill][fill]" "$rowConstraints": "[][][50][::80][][][][][]" } ) { name: "this" @@ -46,7 +46,7 @@ new FormModel { name: "textField4" "text": "Dext field" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 6 0" + "value": "cell 7 0" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label2" @@ -74,16 +74,33 @@ new FormModel { } ) add( new FormComponent( "javax.swing.JComboBox" ) { name: "comboBox1" + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "Dext" + addElement( "Dext" ) + } auxiliary() { "JavaCodeGenerator.typeParameters": "String" } }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 4 1" } ) + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "comboBox2" + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "Dext" + addElement( "Dext" ) + } + "editable": true + auxiliary() { + "JavaCodeGenerator.typeParameters": "String" + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 5 1" + } ) add( new FormComponent( "javax.swing.JSpinner" ) { name: "spinner1" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 5 1" + "value": "cell 6 1" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label6" @@ -112,7 +129,7 @@ new FormModel { name: "textField2" "text": "Dext field" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 6 2" + "value": "cell 7 2" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label7" @@ -184,7 +201,7 @@ new FormModel { name: "textField3" "text": "Dext field" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 6 3" + "value": "cell 7 3" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label3" @@ -195,7 +212,7 @@ new FormModel { add( new FormComponent( "javax.swing.JSlider" ) { name: "slider1" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 4 6 1" + "value": "cell 1 4 7 1" } ) add( new FormComponent( "javax.swing.JSlider" ) { name: "slider6" @@ -203,7 +220,7 @@ new FormModel { "majorTickSpacing": 25 "minorTickSpacing": 5 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 4 6 1" + "value": "cell 1 4 7 1" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label8" @@ -217,7 +234,7 @@ new FormModel { "majorTickSpacing": 25 "minorTickSpacing": 5 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 5 6 1" + "value": "cell 1 5 7 1" } ) add( new FormComponent( "javax.swing.JSlider" ) { name: "slider8" @@ -226,7 +243,7 @@ new FormModel { "majorTickSpacing": 25 "minorTickSpacing": 5 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 5 6 1" + "value": "cell 1 5 7 1" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label4" @@ -238,19 +255,19 @@ new FormModel { name: "progressBar1" "value": 30 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 6 6 1" + "value": "cell 1 6 7 1" } ) add( new FormComponent( "javax.swing.JProgressBar" ) { name: "progressBar3" "stringPainted": true "value": 30 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 6 6 1" + "value": "cell 1 6 7 1" } ) add( new FormComponent( "javax.swing.JSeparator" ) { name: "separator1" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 6 6 1" + "value": "cell 1 6 7 1" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label5" @@ -262,7 +279,7 @@ new FormModel { name: "slider2" "orientation": 1 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 7 6 1" + "value": "cell 1 7 7 1" } ) add( new FormComponent( "javax.swing.JSlider" ) { name: "slider3" @@ -271,14 +288,14 @@ new FormModel { "majorTickSpacing": 25 "minorTickSpacing": 5 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 7 6 1" + "value": "cell 1 7 7 1" } ) add( new FormComponent( "javax.swing.JProgressBar" ) { name: "progressBar2" "orientation": 1 "value": 30 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 7 6 1" + "value": "cell 1 7 7 1" } ) add( new FormComponent( "javax.swing.JProgressBar" ) { name: "progressBar4" @@ -286,12 +303,12 @@ new FormModel { "stringPainted": true "value": 30 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 7 6 1" + "value": "cell 1 7 7 1" } ) add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) { name: "hSpacer1" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 7 6 1,growx" + "value": "cell 1 7 7 1,growx" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "label9" @@ -306,7 +323,7 @@ new FormModel { "majorTickSpacing": 25 "minorTickSpacing": 5 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 8 6 1" + "value": "cell 1 8 7 1" } ) add( new FormComponent( "javax.swing.JSlider" ) { name: "slider5" @@ -316,12 +333,12 @@ new FormModel { "majorTickSpacing": 25 "minorTickSpacing": 5 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 8 6 1" + "value": "cell 1 8 7 1" } ) add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) { name: "hSpacer2" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 8 6 1,growx" + "value": "cell 1 8 7 1,growx" } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) 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..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 @@ -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 ) { @@ -110,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 ) { @@ -129,6 +151,21 @@ public class FlatCustomBordersTest } ); } + private void applyCustomComboBoxRendererBorder( JComboBox comboBox ) { + applyCustomComboBoxRendererBorder( comboBox, new LineBorder( ORANGE, UIScale.scale( 6 ) ) ); + } + + 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 diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.java index d0cb244f..c37f93fa 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.java @@ -73,6 +73,25 @@ public class FlatPaintingTest repaint(); } + private void offsetChanged() { + float offset = (float) offsetSpinner.getValue(); + System.out.println( offset ); + + arrowPainter5.setYOffset( offset ); + arrowPainter6.setYOffset( -offset ); + + arrowPainter7.setXOffset( offset ); + arrowPainter8.setXOffset( -offset ); + + arrowPainter13.setYOffset( offset ); + arrowPainter14.setYOffset( -offset ); + + arrowPainter15.setXOffset( offset ); + arrowPainter16.setXOffset( -offset ); + + repaint(); + } + private void vectorChanged() { boolean vector = vectorCheckBox.isSelected(); @@ -84,7 +103,7 @@ public class FlatPaintingTest repaint(); } - private void checkBox1ActionPerformed() { + private void arrowButtonChanged() { boolean button = buttonCheckBox.isSelected(); FlatTestFrame.updateComponentsRecur( (Container) getViewport().getView(), (c, type) -> { @@ -143,11 +162,11 @@ public class FlatPaintingTest FlatPaintingTest.ArrowPainter arrowPainter3 = new FlatPaintingTest.ArrowPainter(); FlatPaintingTest.ArrowPainter arrowPainter4 = new FlatPaintingTest.ArrowPainter(); JPanel panel1 = new JPanel(); - FlatPaintingTest.ArrowPainter arrowPainter5 = new FlatPaintingTest.ArrowPainter(); - FlatPaintingTest.ArrowPainter arrowPainter6 = new FlatPaintingTest.ArrowPainter(); + arrowPainter5 = new FlatPaintingTest.ArrowPainter(); + arrowPainter6 = new FlatPaintingTest.ArrowPainter(); JPanel panel2 = new JPanel(); - FlatPaintingTest.ArrowPainter arrowPainter7 = new FlatPaintingTest.ArrowPainter(); - FlatPaintingTest.ArrowPainter arrowPainter8 = new FlatPaintingTest.ArrowPainter(); + arrowPainter7 = new FlatPaintingTest.ArrowPainter(); + arrowPainter8 = new FlatPaintingTest.ArrowPainter(); JPanel panel5 = new JPanel(); JLabel arrowWidthLabel = new JLabel(); arrowWidthSpinner = new JSpinner(); @@ -155,6 +174,8 @@ public class FlatPaintingTest arrowHeightSpinner = new JSpinner(); JLabel arrowSizeLabel = new JLabel(); arrowSizeSpinner = new JSpinner(); + JLabel offsetLabel = new JLabel(); + offsetSpinner = new JSpinner(); vectorCheckBox = new JCheckBox(); buttonCheckBox = new JCheckBox(); FlatPaintingTest.ArrowPainter arrowPainter9 = new FlatPaintingTest.ArrowPainter(); @@ -162,11 +183,11 @@ public class FlatPaintingTest FlatPaintingTest.ArrowPainter arrowPainter11 = new FlatPaintingTest.ArrowPainter(); FlatPaintingTest.ArrowPainter arrowPainter12 = new FlatPaintingTest.ArrowPainter(); JPanel panel3 = new JPanel(); - FlatPaintingTest.ArrowPainter arrowPainter13 = new FlatPaintingTest.ArrowPainter(); - FlatPaintingTest.ArrowPainter arrowPainter14 = new FlatPaintingTest.ArrowPainter(); + arrowPainter13 = new FlatPaintingTest.ArrowPainter(); + arrowPainter14 = new FlatPaintingTest.ArrowPainter(); JPanel panel4 = new JPanel(); - FlatPaintingTest.ArrowPainter arrowPainter15 = new FlatPaintingTest.ArrowPainter(); - FlatPaintingTest.ArrowPainter arrowPainter16 = new FlatPaintingTest.ArrowPainter(); + arrowPainter15 = new FlatPaintingTest.ArrowPainter(); + arrowPainter16 = new FlatPaintingTest.ArrowPainter(); //======== this ======== setBorder(null); @@ -519,6 +540,7 @@ public class FlatPaintingTest "[]" + "[]" + "[]" + + "[]" + "[]")); //---- arrowWidthLabel ---- @@ -548,17 +570,26 @@ public class FlatPaintingTest arrowSizeSpinner.addChangeListener(e -> arrowSizeChanged()); panel5.add(arrowSizeSpinner, "cell 1 2"); + //---- offsetLabel ---- + offsetLabel.setText("Offset:"); + panel5.add(offsetLabel, "cell 0 3"); + + //---- offsetSpinner ---- + offsetSpinner.setModel(new SpinnerNumberModel(1.0F, null, null, 0.05F)); + offsetSpinner.addChangeListener(e -> offsetChanged()); + panel5.add(offsetSpinner, "cell 1 3"); + //---- vectorCheckBox ---- vectorCheckBox.setText("vector"); vectorCheckBox.addActionListener(e -> vectorChanged()); - panel5.add(vectorCheckBox, "cell 0 3 2 1,alignx left,growx 0"); + panel5.add(vectorCheckBox, "cell 0 4 2 1,alignx left,growx 0"); //---- buttonCheckBox ---- buttonCheckBox.setText("FlatArrowButton"); - buttonCheckBox.addActionListener(e -> checkBox1ActionPerformed()); - panel5.add(buttonCheckBox, "cell 0 4 2 1,alignx left,growx 0"); + buttonCheckBox.addActionListener(e -> arrowButtonChanged()); + panel5.add(buttonCheckBox, "cell 0 5 2 1,alignx left,growx 0"); } - flatTestPanel1.add(panel5, "cell 6 5,aligny top,growy 0"); + flatTestPanel1.add(panel5, "cell 6 5 1 2,aligny top,growy 0"); //---- arrowPainter9 ---- arrowPainter9.setScale(8.0F); @@ -635,11 +666,20 @@ public class FlatPaintingTest } // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + private FlatPaintingTest.ArrowPainter arrowPainter5; + private FlatPaintingTest.ArrowPainter arrowPainter6; + private FlatPaintingTest.ArrowPainter arrowPainter7; + private FlatPaintingTest.ArrowPainter arrowPainter8; private JSpinner arrowWidthSpinner; private JSpinner arrowHeightSpinner; private JSpinner arrowSizeSpinner; + private JSpinner offsetSpinner; private JCheckBox vectorCheckBox; private JCheckBox buttonCheckBox; + private FlatPaintingTest.ArrowPainter arrowPainter13; + private FlatPaintingTest.ArrowPainter arrowPainter14; + private FlatPaintingTest.ArrowPainter arrowPainter15; + private FlatPaintingTest.ArrowPainter arrowPainter16; // JFormDesigner - End of variables declaration //GEN-END:variables //---- class BorderPainter ------------------------------------------------ @@ -792,8 +832,8 @@ public class FlatPaintingTest private int direction = SwingConstants.SOUTH; private boolean chevron = true; private int arrowSize = FlatArrowButton.DEFAULT_ARROW_WIDTH; - private int xOffset = 0; - private int yOffset = 0; + private float xOffset = 0; + private float yOffset = 0; private float scale = 1; private boolean halfWidth; private boolean halfHeight; @@ -845,19 +885,19 @@ public class FlatPaintingTest this.arrowSize = arrowSize; } - public int getXOffset() { + public float getXOffset() { return xOffset; } - public void setXOffset( int xOffset ) { + public void setXOffset( float xOffset ) { this.xOffset = xOffset; } - public int getYOffset() { + public float getYOffset() { return yOffset; } - public void setYOffset( int yOffset ) { + public void setYOffset( float yOffset ) { this.yOffset = yOffset; } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.jfd index 0d6c21c2..bd77fa17 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingTest.jfd @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.3.1.342" Java: "15" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -383,6 +383,9 @@ new FormModel { "h": 10 "halfHeight": true "YOffset": 1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } } ) add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { name: "arrowPainter6" @@ -390,6 +393,9 @@ new FormModel { "h": 10 "halfHeight": true "YOffset": -1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 4 5,align left top,grow 0 0" @@ -403,6 +409,9 @@ new FormModel { "w": 10 "halfWidth": true "XOffset": 1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } } ) add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { name: "arrowPainter8" @@ -411,6 +420,9 @@ new FormModel { "w": 10 "halfWidth": true "XOffset": -1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 5 5,align left top,grow 0 0" @@ -418,7 +430,7 @@ new FormModel { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "hidemode 3" "$columnConstraints": "[fill][fill]" - "$rowConstraints": "[][][][][]" + "$rowConstraints": "[][][][][][]" } ) { name: "panel5" "border": new javax.swing.border.TitledBorder( "Arrow Control" ) @@ -479,6 +491,25 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 2" } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "offsetLabel" + "text": "Offset:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "offsetSpinner" + "model": new javax.swing.SpinnerNumberModel { + stepSize: 0.05f + value: 1.0f + } + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "offsetChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3" + } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "vectorCheckBox" "text": "vector" @@ -487,7 +518,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "vectorChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 3 2 1,alignx left,growx 0" + "value": "cell 0 4 2 1,alignx left,growx 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "buttonCheckBox" @@ -495,12 +526,12 @@ new FormModel { auxiliary() { "JavaCodeGenerator.variableLocal": false } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "checkBox1ActionPerformed", false ) ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "arrowButtonChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 4 2 1,alignx left,growx 0" + "value": "cell 0 5 2 1,alignx left,growx 0" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 6 5,aligny top,growy 0" + "value": "cell 6 5 1 2,aligny top,growy 0" } ) add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { name: "arrowPainter9" @@ -545,6 +576,9 @@ new FormModel { "chevron": false "halfHeight": true "YOffset": 1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } } ) add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { name: "arrowPainter14" @@ -553,6 +587,9 @@ new FormModel { "chevron": false "halfHeight": true "YOffset": -1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 4 6,align left top,grow 0 0" @@ -567,6 +604,9 @@ new FormModel { "chevron": false "halfWidth": true "XOffset": 1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } } ) add( new FormComponent( "com.formdev.flatlaf.testing.FlatPaintingTest$ArrowPainter" ) { name: "arrowPainter16" @@ -576,6 +616,9 @@ new FormModel { "chevron": false "halfWidth": true "XOffset": -1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 5 6,align left top,grow 0 0" diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java index 1d5cb38a..07d3e630 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java @@ -23,6 +23,7 @@ import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -284,6 +285,8 @@ public class FlatTestFrame Properties properties = new Properties(); try( InputStream in = new FileInputStream( "lafs.properties" ) ) { properties.load( in ); + } catch( FileNotFoundException ex ) { + // ignore } catch( IOException ex ) { ex.printStackTrace(); } 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" diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties index cc4d76a7..589e78dd 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties @@ -132,7 +132,7 @@ ComboBox.buttonEditableBackground = #ccc ComboBox.focusedBackground = #ff8 ComboBox.buttonFocusedBackground = #ff0 -ComboBox.popupFocusedBackground = #ffc +ComboBox.popupBackground = #ffc #---- Component ----