ComboBox: fixed minimum width if focusWidth > 0 (to be equal with button minimum width)

added some unit tests to compare component sizes
This commit is contained in:
Karl Tauber
2021-07-05 11:07:32 +02:00
parent 4507ce359d
commit 0b127caa83
7 changed files with 310 additions and 4 deletions

View File

@@ -21,6 +21,12 @@ plugins {
`flatlaf-publish`
}
dependencies {
testImplementation( "org.junit.jupiter:junit-jupiter-api:5.7.2" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-engine" )
testRuntimeOnly( "org.junit.jupiter:junit-jupiter-params" )
}
java {
withSourcesJar()
withJavadocJar()
@@ -52,6 +58,11 @@ tasks {
named<Jar>( "javadocJar" ) {
archiveBaseName.set( "flatlaf" )
}
test {
useJUnitPlatform()
testLogging.exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}
flatlafPublish {

View File

@@ -309,6 +309,9 @@ class LinuxFontPolicy
* - running on JetBrains Runtime 11 or later and scaling is enabled in system Settings
*/
private static boolean isSystemScaling() {
if( GraphicsEnvironment.isHeadless() )
return true;
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getDefaultScreenDevice().getDefaultConfiguration();
return UIScale.getSystemScaleFactor( gc ) > 1;

View File

@@ -501,9 +501,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;

View File

@@ -534,7 +534,8 @@ 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;
}

View File

@@ -0,0 +1,209 @@
/*
* 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 new float[] { 1f, 1.25f, 1.5f, 1.75f, 2f, 2.25f, 2.5f, 3f, 4f };
}
@ParameterizedTest
@MethodSource( "factors" )
void sizes( float factor ) {
TestUtils.scaleFont( factor );
// TODO on some scale factors the combobox/spinner sizes are slightly different
// because different size calculation methods and rounding
boolean testComboBoxAndSpinner = (UIManager.getInt( "Component.focusWidth" ) > 0)
? (factor != 1.25 && factor != 2.25)
: (factor != 1.75);
// 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() );
if( testComboBoxAndSpinner )
assertEquals( textFieldSize, spinner.getPreferredSize() );
// should have same default size (minimumWidth is 72)
JButton button = new JButton( "text" );
JComboBox<String> comboBox = new JComboBox<>();
JComboBox<String> comboBoxEditable = new JComboBox<>();
comboBoxEditable.setEditable( true );
Dimension buttonSize = button.getPreferredSize();
if( testComboBoxAndSpinner ) {
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 );
JComboBox<String> comboBox = new JComboBox<>();
JComboBox<String> comboBox2 = new JComboBox<>();
JComboBox<String> comboBox3 = new JComboBox<>();
JComboBox<String> comboBox4 = new JComboBox<>();
applyCustomComboBoxRendererBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 3 ) ) );
applyCustomComboBoxRendererBorder( comboBox3, new BorderWithIcon() );
applyCustomComboBoxRendererBorder( comboBox4, null );
Dimension size = comboBox.getPreferredSize();
assertEquals( size, comboBox2.getPreferredSize() );
assertEquals( size, comboBox3.getPreferredSize() );
assertEquals( size, comboBox4.getPreferredSize() );
TestUtils.resetFont();
}
@SuppressWarnings( "unchecked" )
private void applyCustomComboBoxRendererBorder( JComboBox<String> comboBox, Border border ) {
BasicComboBoxRenderer customRenderer = new BasicComboBoxRenderer();
customRenderer.setBorder( border );
comboBox.setRenderer( customRenderer );
}
@ParameterizedTest
@MethodSource( "factors" )
void comboBoxEditable( float factor ) {
TestUtils.scaleFont( factor );
JComboBox<String> comboBox = new JComboBox<>();
JComboBox<String> comboBox2 = new JComboBox<>();
JComboBox<String> comboBox3 = new JComboBox<>();
JComboBox<String> comboBox4 = new JComboBox<>();
comboBox.setEditable( true );
comboBox2.setEditable( true );
comboBox3.setEditable( true );
comboBox4.setEditable( true );
applyCustomComboBoxEditorBorder( comboBox2, new LineBorder( Color.orange, UIScale.scale( 3 ) ) );
applyCustomComboBoxEditorBorder( comboBox3, new BorderWithIcon() );
applyCustomComboBoxEditorBorder( comboBox4, null );
Dimension size = comboBox.getPreferredSize();
assertEquals( size.width, comboBox2.getPreferredSize().width );
assertEquals( size.height + (2 * UIScale.scale( 3 )), comboBox2.getPreferredSize().height );
assertEquals( size, comboBox3.getPreferredSize() );
assertEquals( size, comboBox4.getPreferredSize() );
TestUtils.resetFont();
}
private void applyCustomComboBoxEditorBorder( JComboBox<String> 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 );
}
}
}

View File

@@ -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 );
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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 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 );
}
}