From 4e44e25d3032f4c1f8fb2c24b002505252ece36f Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 3 Dec 2022 19:17:10 +0100 Subject: [PATCH] macOS themes: fix horizontal centering of combobox arrows (issue #497; PR #533) --- .../formdev/flatlaf/ui/FlatComboBoxUI.java | 21 +++++--- .../testing/FlatPaintingArrowsTest.java | 48 +++++++++++++++---- .../testing/FlatPaintingArrowsTest.jfd | 22 +++++++-- 3 files changed, 71 insertions(+), 20 deletions(-) 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 04cbff2fa..4dc256f3c 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 @@ -766,12 +766,6 @@ protected class FlatComboBoxButton protected FlatComboBoxButton() { this( SwingConstants.SOUTH, arrowType, buttonArrowColor, buttonDisabledArrowColor, buttonHoverArrowColor, null, buttonPressedArrowColor, null ); - - if( isMacStyle() ) { - setArrowWidth( 7 ); - setArrowThickness( 1.5f ); - setRoundBorderAutoXOffset( false ); - } } protected FlatComboBoxButton( int direction, String type, Color foreground, Color disabledForeground, @@ -786,6 +780,21 @@ protected void updateStyle() { buttonHoverArrowColor, null, buttonPressedArrowColor, null ); } + @Override + public int getArrowWidth() { + return isMacStyle() ? (getWidth() % 2 == 0 ? 6 : 7) : super.getArrowWidth(); + } + + @Override + public float getArrowThickness() { + return isMacStyle() ? 1.5f : super.getArrowThickness(); + } + + @Override + public boolean isRoundBorderAutoXOffset() { + return isMacStyle() ? false : super.isRoundBorderAutoXOffset(); + } + @Override protected boolean isHover() { return super.isHover() || (!comboBox.isEditable() ? hover : false); diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingArrowsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingArrowsTest.java index ba078f5f3..c0cae1803 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingArrowsTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingArrowsTest.java @@ -23,6 +23,7 @@ import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import java.beans.Beans; import java.util.Hashtable; import javax.swing.*; import javax.swing.border.*; @@ -91,10 +92,15 @@ private void scaleChanged() { private void pixelsChanged() { boolean paintPixels = pixelsCheckBox.isSelected(); + boolean paintVector = vectorCheckBox.isSelected(); + + vectorCheckBox.setEnabled( paintPixels ); FlatTestFrame.updateComponentsRecur( panel, (c, type) -> { - if( c instanceof ArrowPainter ) + if( c instanceof ArrowPainter ) { ((ArrowPainter)c).paintPixels = paintPixels; + ((ArrowPainter)c).paintVector = paintVector; + } } ); panel.repaint(); @@ -189,6 +195,7 @@ private void initComponents() { JLabel scaleLabel = new JLabel(); scaleSlider = new JSlider(); pixelsCheckBox = new JCheckBox(); + vectorCheckBox = new JCheckBox(); pixelsScaleLabel = new JLabel(); pixelsScaleSlider = new JSlider(); JPanel panel55 = new JPanel(); @@ -347,10 +354,12 @@ private void initComponents() { //======== panel1 ======== { panel1.setLayout(new MigLayout( - "hidemode 3", + "flowy,hidemode 3", // columns "[fill]" + "[grow,fill]para" + + "[fill]" + + "[fill]" + "[fill]", // rows "[]" + @@ -380,11 +389,18 @@ private void initComponents() { pixelsCheckBox.addActionListener(e -> pixelsChanged()); panel1.add(pixelsCheckBox, "cell 2 0"); + //---- vectorCheckBox ---- + vectorCheckBox.setText("vector"); + vectorCheckBox.setMnemonic('V'); + vectorCheckBox.setSelected(true); + vectorCheckBox.addActionListener(e -> pixelsChanged()); + panel1.add(vectorCheckBox, "cell 2 0"); + //---- pixelsScaleLabel ---- pixelsScaleLabel.setText("Scale:"); pixelsScaleLabel.setLabelFor(pixelsScaleSlider); pixelsScaleLabel.setDisplayedMnemonic('C'); - panel1.add(pixelsScaleLabel, "cell 2 0"); + panel1.add(pixelsScaleLabel, "cell 3 0"); //---- pixelsScaleSlider ---- pixelsScaleSlider.setMinimum(100); @@ -395,7 +411,7 @@ private void initComponents() { pixelsScaleSlider.setPaintTicks(true); pixelsScaleSlider.setPaintLabels(true); pixelsScaleSlider.addChangeListener(e -> pixelsScaleChanged()); - panel1.add(pixelsScaleSlider, "cell 2 0"); + panel1.add(pixelsScaleSlider, "cell 4 0"); //======== panel55 ======== { @@ -467,7 +483,7 @@ private void initComponents() { buttonCheckBox.addActionListener(e -> arrowButtonChanged()); panel55.add(buttonCheckBox, "cell 10 0,alignx left,growx 0"); } - panel1.add(panel55, "cell 0 1 3 1"); + panel1.add(panel55, "cell 0 1 5 1"); } add(panel1, BorderLayout.NORTH); // JFormDesigner - End of component initialization //GEN-END:initComponents @@ -486,6 +502,7 @@ private void initComponents() { private FlatPaintingArrowsTest.ArrowPainter arrowPainter16; private JSlider scaleSlider; private JCheckBox pixelsCheckBox; + private JCheckBox vectorCheckBox; private JLabel pixelsScaleLabel; private JSlider pixelsScaleSlider; private JSpinner arrowWidthSpinner; @@ -515,6 +532,7 @@ public static class ArrowPainter float arrowThickness = 1; int scale = 4; boolean paintPixels; + boolean paintVector; float paintPixelsScale = 1; public ArrowPainter() { @@ -619,18 +637,27 @@ protected void paintComponent( Graphics g ) { // paint icon to buffered image BufferedImage bi = new BufferedImage( bitmapWidth, bitmapHeight, BufferedImage.TYPE_INT_ARGB ); - Graphics bg = bi.createGraphics(); + Graphics2D bg = bi.createGraphics(); try { FlatUIUtils.setRenderingHints( bg ); + bg.scale( paintPixelsScale, paintPixelsScale ); bg.setColor( Color.blue ); - paintArrow( (Graphics2D) bg, bitmapWidth, bitmapHeight ); + paintArrow( bg, width, height ); } finally { bg.dispose(); } // draw scaled-up image g2.drawImage( bi, 0, 0, getWidth(), getHeight(), null ); + + if( paintVector ) { + AffineTransform oldTransform = g2.getTransform(); + g2.scale( scale, scale ); + g.setColor( new Color( (Color.red.getRGB() & 0xffffff) | (0xa0 << 24), true ) ); + paintArrow( g2, width, height ); + g2.setTransform( oldTransform ); + } } // paint border and grid @@ -660,8 +687,11 @@ protected void paintComponent( Graphics g ) { } private void paintArrow( Graphics2D g, int width, int height ) { - FlatUIUtils.paintArrow( g, 0, 0, width, height, - direction, chevron, arrowSize, arrowThickness, xOffset, yOffset ); + // do not paint in JFormDesigner because it may use a different FlatLaf version + if( !Beans.isDesignTime() ) { + FlatUIUtils.paintArrow( g, 0, 0, width, height, + direction, chevron, arrowSize, arrowThickness, xOffset, yOffset ); + } if( button ) { FlatArrowButton arrowButton = new FlatArrowButton( direction, diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingArrowsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingArrowsTest.jfd index f36dddc05..38cb3f5b8 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingArrowsTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatPaintingArrowsTest.jfd @@ -184,8 +184,8 @@ new FormModel { "value": "Center" } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { - "$layoutConstraints": "hidemode 3" - "$columnConstraints": "[fill][grow,fill]para[fill]" + "$layoutConstraints": "flowy,hidemode 3" + "$columnConstraints": "[fill][grow,fill]para[fill][fill][fill]" "$rowConstraints": "[][]" } ) { name: "panel1" @@ -225,6 +225,18 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 0" } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "vectorCheckBox" + "text": "vector" + "mnemonic": 86 + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "pixelsChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 0" + } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "pixelsScaleLabel" "text": "Scale:" @@ -234,7 +246,7 @@ new FormModel { "JavaCodeGenerator.variableLocal": false } }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 0" + "value": "cell 3 0" } ) add( new FormComponent( "javax.swing.JSlider" ) { name: "pixelsScaleSlider" @@ -250,7 +262,7 @@ new FormModel { } addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "pixelsScaleChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 0" + "value": "cell 4 0" } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "hidemode 3" @@ -366,7 +378,7 @@ new FormModel { "value": "cell 10 0,alignx left,growx 0" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 1 3 1" + "value": "cell 0 1 5 1" } ) }, new FormLayoutConstraints( class java.lang.String ) { "value": "North"