diff --git a/CHANGELOG.md b/CHANGELOG.md index 50c674c5..914cbd03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,19 @@ FlatLaf Change Log `JFrame.setDefaultLookAndFeelDecorated(true)` and `JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window. (issue #482) +- ScrollBar: Added UI value `ScrollBar.minimumButtonSize` to specify minimum + scroll arrow button size (if shown). (issue #493) + +#### Fixed bugs + +- ScrollBar: Center and scale arrows in scroll up/down buttons (if shown). + (issue #493) + +#### Incompatibilities + +- Method `FlatUIUtils.paintArrow()` (and class `FlatArrowButton`) now paints + arrows one pixel smaller than before. To fix this, increase parameter + `arrowSize` by one. ## 2.0.2 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 5d006377..df12e0ec 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 @@ -37,7 +37,7 @@ public class FlatArrowButton extends BasicArrowButton implements UIResource { - public static final int DEFAULT_ARROW_WIDTH = 8; + public static final int DEFAULT_ARROW_WIDTH = 9; protected boolean chevron; protected Color foreground; @@ -211,6 +211,6 @@ public class FlatArrowButton if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) ) x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 ); - FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, arrowWidth, xOffset, yOffset ); + FlatUIUtils.paintArrow( g, x, 0, getWidth(), getHeight(), getDirection(), chevron, getArrowWidth(), getXOffset(), getYOffset() ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollBarUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollBarUI.java index baf6a4a8..caffbfde 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollBarUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatScrollBarUI.java @@ -57,6 +57,7 @@ import com.formdev.flatlaf.util.UIScale; * * * + * @uiDefault ScrollBar.minimumButtonSize Dimension * @uiDefault ScrollBar.trackInsets Insets * @uiDefault ScrollBar.thumbInsets Insets * @uiDefault ScrollBar.trackArc int @@ -83,6 +84,7 @@ public class FlatScrollBarUI // overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private) @Styleable protected boolean allowsAbsolutePositioning; + /** @since 2.1 */ @Styleable protected Dimension minimumButtonSize; @Styleable protected Insets trackInsets; @Styleable protected Insets thumbInsets; @Styleable protected int trackArc; @@ -142,6 +144,7 @@ public class FlatScrollBarUI allowsAbsolutePositioning = super.getSupportsAbsolutePositioning(); + minimumButtonSize = UIManager.getDimension( "ScrollBar.minimumButtonSize" ); trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" ); thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" ); trackArc = UIManager.getInt( "ScrollBar.trackArc" ); @@ -171,6 +174,7 @@ public class FlatScrollBarUI protected void uninstallDefaults() { super.uninstallDefaults(); + minimumButtonSize = null; trackInsets = null; thumbInsets = null; hoverTrackColor = null; @@ -451,7 +455,6 @@ public class FlatScrollBarUI super( direction, type, foreground, disabledForeground, hoverForeground, hoverBackground, pressedForeground, pressedBackground ); - setArrowWidth( FlatArrowButton.DEFAULT_ARROW_WIDTH - 2 ); setFocusable( false ); setRequestFocusEnabled( false ); } @@ -461,6 +464,18 @@ public class FlatScrollBarUI null, hoverButtonBackground, null, pressedButtonBackground ); } + @Override + public int getArrowWidth() { + // scale arrow size depending on scroll bar width + // (6 is default arrow width; 10 is base scroll bar width) + int arrowWidth = Math.round( 6 * (scrollBarWidth / 10f) ); + + // compute arrow size that leaves equal space on both sides (arrow is centered) + arrowWidth = scrollBarWidth - (((scrollBarWidth - arrowWidth) / 2) * 2); + + return arrowWidth; + } + @Override protected Color deriveBackground( Color background ) { return FlatUIUtils.deriveColor( background, scrollbar.getBackground() ); @@ -469,8 +484,9 @@ public class FlatScrollBarUI @Override public Dimension getPreferredSize() { if( isShowButtons() ) { - int w = UIScale.scale( scrollBarWidth ); - return new Dimension( w, w ); + int w = UIScale.scale( Math.max( scrollBarWidth, (minimumButtonSize != null) ? minimumButtonSize.width : 0 ) ); + int h = UIScale.scale( Math.max( scrollBarWidth, (minimumButtonSize != null) ? minimumButtonSize.height : 0 ) ); + return new Dimension( w, h ); } else return new Dimension(); } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java index 813848c3..d3aeaf43 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java @@ -1841,7 +1841,7 @@ public class FlatTabbedPaneUI super( direction, arrowType, FlatTabbedPaneUI.this.foreground, FlatTabbedPaneUI.this.disabledForeground, null, buttonHoverBackground, null, buttonPressedBackground ); - setArrowWidth( 10 ); + setArrowWidth( 11 ); } protected void updateStyle() { 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 0d298a0d..2af95f61 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 @@ -786,13 +786,15 @@ public class FlatUIUtils int direction, boolean chevron, int arrowSize, float xOffset, float yOffset ) { // compute arrow width/height - int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) ); - int ah = UIScale.scale( (arrowSize / 2) + (chevron ? 0 : 1) ); + // - make chevron arrows one pixel smaller because coordinates are based on center of pixels (0.5/0.5) + // - make triangle arrows one pixel taller (and round height up) to make them look stronger + float aw = UIScale.scale( arrowSize + (chevron ? -1 : 0) ); + float ah = chevron ? (aw / 2) : UIScale.scale( (arrowSize / 2) + 1 ); // rotate arrow width/height for horizontal directions boolean vert = (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH); if( !vert ) { - int temp = aw; + float temp = aw; aw = ah; ah = temp; } @@ -804,19 +806,19 @@ public class FlatUIUtils // compute arrow location 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 )); + float ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -(ox + aw) ) - aw : Math.round( ox )); + float ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -(oy + ah) ) - ah : Math.round( oy )); // paint arrow g.translate( ax, ay ); /*debug - debugPaintArrow( g, Color.red, vert, aw + extra, ah + extra ); + debugPaintArrow( g, Color.red, vert, Math.round( aw + extra ), Math.round( ah + extra ) ); debug*/ Shape arrowShape = createArrowShape( direction, chevron, aw, ah ); if( chevron ) { Stroke oldStroke = g.getStroke(); g.setStroke( new BasicStroke( UIScale.scale( 1f ) ) ); - g.draw( arrowShape ); + drawShapePure( g, arrowShape ); g.setStroke( oldStroke ); } else { // triangle @@ -892,6 +894,23 @@ debug*/ return path; } + /** + * Draws the given shape with disabled stroke normalization. + * The x/y coordinates of the shape are translated by a half pixel. + * + * @since 2.1 + */ + public static void drawShapePure( Graphics2D g, Shape shape ) { + Object oldStrokeControl = g.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ); + g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE ); + + g.translate( 0.5, 0.5 ); + g.draw( shape ); + g.translate( -0.5, -0.5 ); + + g.setRenderingHint( RenderingHints.KEY_STROKE_CONTROL, oldStrokeControl ); + } + /** * Draws the given string at the specified location. * The provided component is used to query text properties and anti-aliasing hints. diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index fe25729e..e242a1eb 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -555,6 +555,7 @@ RootPane.honorDialogMinimumSizeOnResize = true #---- ScrollBar ---- ScrollBar.width = 10 +ScrollBar.minimumButtonSize = 12,12 ScrollBar.minimumThumbSize = 10,10 ScrollBar.maximumThumbSize = 100000,100000 ScrollBar.trackInsets = 0,0,0,0 diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java index 80900989..4ca37a48 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java @@ -539,6 +539,7 @@ public class TestFlatStyleableInfo "maximumThumbSize", Dimension.class, "allowsAbsolutePositioning", boolean.class, + "minimumButtonSize", Dimension.class, "trackInsets", Insets.class, "thumbInsets", Insets.class, "trackArc", int.class, diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java index 77654ca9..a8c51801 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java @@ -684,6 +684,7 @@ public class TestFlatStyling ui.applyStyle( "maximumThumbSize: 1,2" ); ui.applyStyle( "allowsAbsolutePositioning: true" ); + ui.applyStyle( "minimumButtonSize: 1,2" ); ui.applyStyle( "trackInsets: 1,2,3,4" ); ui.applyStyle( "thumbInsets: 1,2,3,4" ); ui.applyStyle( "trackArc: 5" ); diff --git a/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatTaskPaneUI.java b/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatTaskPaneUI.java index f336a370..6fc0f7c0 100644 --- a/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatTaskPaneUI.java +++ b/flatlaf-swingx/src/main/java/com/formdev/flatlaf/swingx/ui/FlatTaskPaneUI.java @@ -217,8 +217,8 @@ public class FlatTaskPaneUI Graphics2D g2 = (Graphics2D) g; // scale chevron size - float cw = scale( 6f ); - float ch = scale( 3f ); + float cw = scale( 7f ); + float ch = scale( 3.5f ); // create arrow shape int direction = group.isCollapsed() ? SwingConstants.SOUTH : SwingConstants.NORTH; @@ -237,9 +237,9 @@ public class FlatTaskPaneUI // paint g2.translate( cx, cy ); - g2.draw( arrowShape ); + FlatUIUtils.drawShapePure( g2, arrowShape ); g2.translate( 0, offset ); - g2.draw( arrowShape ); + FlatUIUtils.drawShapePure( g2, arrowShape ); g2.translate( -cx, -(cy + offset) ); } diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt index d0429198..78fa7538 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt @@ -862,6 +862,7 @@ ScrollBar.hoverThumbColor #6e767a HSL 200 5 45 com.formdev.flatlaf.u ScrollBar.hoverThumbWithTrack false ScrollBar.hoverTrackColor #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(4%) ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI] +ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI] ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI] ScrollBar.pressedButtonBackground #54595c HSL 203 5 35 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%) ScrollBar.pressedThumbColor #7a8387 HSL 198 5 50 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15%) diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt index 8cf90058..40cce209 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt @@ -867,6 +867,7 @@ ScrollBar.hoverThumbColor #c3c3c3 HSL 0 0 76 com.formdev.flatlaf.u ScrollBar.hoverThumbWithTrack false ScrollBar.hoverTrackColor #ededed HSL 0 0 93 com.formdev.flatlaf.util.DerivedColor [UI] darken(3%) ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI] +ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI] ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI] ScrollBar.pressedButtonBackground #d9d9d9 HSL 0 0 85 com.formdev.flatlaf.util.DerivedColor [UI] darken(10%) ScrollBar.pressedThumbColor #a9a9a9 HSL 0 0 66 com.formdev.flatlaf.util.DerivedColor [UI] darken(20%) diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt index d81a5749..429e7366 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt @@ -874,6 +874,7 @@ ScrollBar.hoverThumbColor #ff0000 HSL 0 100 50 javax.swing.plaf.Colo ScrollBar.hoverThumbWithTrack false ScrollBar.hoverTrackColor #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI] ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI] +ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI] ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI] ScrollBar.pressedThumbWithTrack false ScrollBar.showButtons false 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 c1101e75..e1de4a2b 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 @@ -673,7 +673,7 @@ public class FlatPaintingTest panel5.add(arrowSizeLabel, "cell 0 2"); //---- arrowSizeSpinner ---- - arrowSizeSpinner.setModel(new SpinnerNumberModel(8, 2, null, 1)); + arrowSizeSpinner.setModel(new SpinnerNumberModel(9, 2, null, 1)); arrowSizeSpinner.addChangeListener(e -> arrowSizeChanged()); panel5.add(arrowSizeSpinner, "cell 1 2"); 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 3b23d601..bc82ee18 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 @@ -564,7 +564,7 @@ new FormModel { name: "arrowSizeSpinner" "model": new javax.swing.SpinnerNumberModel { minimum: 2 - value: 8 + value: 9 } auxiliary() { "JavaCodeGenerator.variableLocal": false diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt index e719971f..c06f6c8d 100644 --- a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt @@ -658,6 +658,7 @@ ScrollBar.hoverThumbColor ScrollBar.hoverThumbWithTrack ScrollBar.hoverTrackColor ScrollBar.maximumThumbSize +ScrollBar.minimumButtonSize ScrollBar.minimumThumbSize ScrollBar.pressedButtonBackground ScrollBar.pressedThumbColor