ScrollBar:

- added `ScrollBar.minimumButtonSize` to specify minimum scroll arrow button size
- center and scale arrows in scroll up/down buttons

(issue #493)
This commit is contained in:
Karl Tauber
2022-03-13 10:50:49 +01:00
parent ab58101ce3
commit 99f7b9ad84
15 changed files with 74 additions and 19 deletions

View File

@@ -9,6 +9,19 @@ FlatLaf Change Log
`JFrame.setDefaultLookAndFeelDecorated(true)` and `JFrame.setDefaultLookAndFeelDecorated(true)` and
`JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window. `JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window.
(issue #482) (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 ## 2.0.2

View File

@@ -37,7 +37,7 @@ public class FlatArrowButton
extends BasicArrowButton extends BasicArrowButton
implements UIResource implements UIResource
{ {
public static final int DEFAULT_ARROW_WIDTH = 8; public static final int DEFAULT_ARROW_WIDTH = 9;
protected boolean chevron; protected boolean chevron;
protected Color foreground; protected Color foreground;
@@ -211,6 +211,6 @@ public class FlatArrowButton
if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) ) if( vert && parent instanceof JComponent && FlatUIUtils.hasRoundBorder( (JComponent) parent ) )
x -= scale( parent.getComponentOrientation().isLeftToRight() ? 1 : -1 ); 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() );
} }
} }

View File

@@ -57,6 +57,7 @@ import com.formdev.flatlaf.util.UIScale;
* *
* <!-- FlatScrollBarUI --> * <!-- FlatScrollBarUI -->
* *
* @uiDefault ScrollBar.minimumButtonSize Dimension
* @uiDefault ScrollBar.trackInsets Insets * @uiDefault ScrollBar.trackInsets Insets
* @uiDefault ScrollBar.thumbInsets Insets * @uiDefault ScrollBar.thumbInsets Insets
* @uiDefault ScrollBar.trackArc int * @uiDefault ScrollBar.trackArc int
@@ -83,6 +84,7 @@ public class FlatScrollBarUI
// overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private) // overrides BasicScrollBarUI.supportsAbsolutePositioning (which is private)
@Styleable protected boolean allowsAbsolutePositioning; @Styleable protected boolean allowsAbsolutePositioning;
/** @since 2.1 */ @Styleable protected Dimension minimumButtonSize;
@Styleable protected Insets trackInsets; @Styleable protected Insets trackInsets;
@Styleable protected Insets thumbInsets; @Styleable protected Insets thumbInsets;
@Styleable protected int trackArc; @Styleable protected int trackArc;
@@ -142,6 +144,7 @@ public class FlatScrollBarUI
allowsAbsolutePositioning = super.getSupportsAbsolutePositioning(); allowsAbsolutePositioning = super.getSupportsAbsolutePositioning();
minimumButtonSize = UIManager.getDimension( "ScrollBar.minimumButtonSize" );
trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" ); trackInsets = UIManager.getInsets( "ScrollBar.trackInsets" );
thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" ); thumbInsets = UIManager.getInsets( "ScrollBar.thumbInsets" );
trackArc = UIManager.getInt( "ScrollBar.trackArc" ); trackArc = UIManager.getInt( "ScrollBar.trackArc" );
@@ -171,6 +174,7 @@ public class FlatScrollBarUI
protected void uninstallDefaults() { protected void uninstallDefaults() {
super.uninstallDefaults(); super.uninstallDefaults();
minimumButtonSize = null;
trackInsets = null; trackInsets = null;
thumbInsets = null; thumbInsets = null;
hoverTrackColor = null; hoverTrackColor = null;
@@ -451,7 +455,6 @@ public class FlatScrollBarUI
super( direction, type, foreground, disabledForeground, super( direction, type, foreground, disabledForeground,
hoverForeground, hoverBackground, pressedForeground, pressedBackground ); hoverForeground, hoverBackground, pressedForeground, pressedBackground );
setArrowWidth( FlatArrowButton.DEFAULT_ARROW_WIDTH - 2 );
setFocusable( false ); setFocusable( false );
setRequestFocusEnabled( false ); setRequestFocusEnabled( false );
} }
@@ -461,6 +464,18 @@ public class FlatScrollBarUI
null, hoverButtonBackground, null, pressedButtonBackground ); 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 @Override
protected Color deriveBackground( Color background ) { protected Color deriveBackground( Color background ) {
return FlatUIUtils.deriveColor( background, scrollbar.getBackground() ); return FlatUIUtils.deriveColor( background, scrollbar.getBackground() );
@@ -469,8 +484,9 @@ public class FlatScrollBarUI
@Override @Override
public Dimension getPreferredSize() { public Dimension getPreferredSize() {
if( isShowButtons() ) { if( isShowButtons() ) {
int w = UIScale.scale( scrollBarWidth ); int w = UIScale.scale( Math.max( scrollBarWidth, (minimumButtonSize != null) ? minimumButtonSize.width : 0 ) );
return new Dimension( w, w ); int h = UIScale.scale( Math.max( scrollBarWidth, (minimumButtonSize != null) ? minimumButtonSize.height : 0 ) );
return new Dimension( w, h );
} else } else
return new Dimension(); return new Dimension();
} }

View File

@@ -1841,7 +1841,7 @@ public class FlatTabbedPaneUI
super( direction, arrowType, super( direction, arrowType,
FlatTabbedPaneUI.this.foreground, FlatTabbedPaneUI.this.disabledForeground, FlatTabbedPaneUI.this.foreground, FlatTabbedPaneUI.this.disabledForeground,
null, buttonHoverBackground, null, buttonPressedBackground ); null, buttonHoverBackground, null, buttonPressedBackground );
setArrowWidth( 10 ); setArrowWidth( 11 );
} }
protected void updateStyle() { protected void updateStyle() {

View File

@@ -786,13 +786,15 @@ public class FlatUIUtils
int direction, boolean chevron, int arrowSize, float xOffset, float yOffset ) int direction, boolean chevron, int arrowSize, float xOffset, float yOffset )
{ {
// compute arrow width/height // compute arrow width/height
int aw = UIScale.scale( arrowSize + (chevron ? 0 : 1) ); // - make chevron arrows one pixel smaller because coordinates are based on center of pixels (0.5/0.5)
int ah = UIScale.scale( (arrowSize / 2) + (chevron ? 0 : 1) ); // - 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 // rotate arrow width/height for horizontal directions
boolean vert = (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH); boolean vert = (direction == SwingConstants.NORTH || direction == SwingConstants.SOUTH);
if( !vert ) { if( !vert ) {
int temp = aw; float temp = aw;
aw = ah; aw = ah;
ah = temp; ah = temp;
} }
@@ -804,19 +806,19 @@ public class FlatUIUtils
// compute arrow location // compute arrow location
float ox = ((width - (aw + extra)) / 2f) + UIScale.scale( xOffset ); float ox = ((width - (aw + extra)) / 2f) + UIScale.scale( xOffset );
float oy = ((height - (ah + extra)) / 2f) + UIScale.scale( yOffset ); float oy = ((height - (ah + extra)) / 2f) + UIScale.scale( yOffset );
int ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -ox ) : Math.round( ox )); float ax = x + ((direction == SwingConstants.WEST) ? -Math.round( -(ox + aw) ) - aw : Math.round( ox ));
int ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -oy ) : Math.round( oy )); float ay = y + ((direction == SwingConstants.NORTH) ? -Math.round( -(oy + ah) ) - ah : Math.round( oy ));
// paint arrow // paint arrow
g.translate( ax, ay ); g.translate( ax, ay );
/*debug /*debug
debugPaintArrow( g, Color.red, vert, aw + extra, ah + extra ); debugPaintArrow( g, Color.red, vert, Math.round( aw + extra ), Math.round( ah + extra ) );
debug*/ debug*/
Shape arrowShape = createArrowShape( direction, chevron, aw, ah ); Shape arrowShape = createArrowShape( direction, chevron, aw, ah );
if( chevron ) { if( chevron ) {
Stroke oldStroke = g.getStroke(); Stroke oldStroke = g.getStroke();
g.setStroke( new BasicStroke( UIScale.scale( 1f ) ) ); g.setStroke( new BasicStroke( UIScale.scale( 1f ) ) );
g.draw( arrowShape ); drawShapePure( g, arrowShape );
g.setStroke( oldStroke ); g.setStroke( oldStroke );
} else { } else {
// triangle // triangle
@@ -892,6 +894,23 @@ debug*/
return path; 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. * Draws the given string at the specified location.
* The provided component is used to query text properties and anti-aliasing hints. * The provided component is used to query text properties and anti-aliasing hints.

View File

@@ -555,6 +555,7 @@ RootPane.honorDialogMinimumSizeOnResize = true
#---- ScrollBar ---- #---- ScrollBar ----
ScrollBar.width = 10 ScrollBar.width = 10
ScrollBar.minimumButtonSize = 12,12
ScrollBar.minimumThumbSize = 10,10 ScrollBar.minimumThumbSize = 10,10
ScrollBar.maximumThumbSize = 100000,100000 ScrollBar.maximumThumbSize = 100000,100000
ScrollBar.trackInsets = 0,0,0,0 ScrollBar.trackInsets = 0,0,0,0

View File

@@ -539,6 +539,7 @@ public class TestFlatStyleableInfo
"maximumThumbSize", Dimension.class, "maximumThumbSize", Dimension.class,
"allowsAbsolutePositioning", boolean.class, "allowsAbsolutePositioning", boolean.class,
"minimumButtonSize", Dimension.class,
"trackInsets", Insets.class, "trackInsets", Insets.class,
"thumbInsets", Insets.class, "thumbInsets", Insets.class,
"trackArc", int.class, "trackArc", int.class,

View File

@@ -684,6 +684,7 @@ public class TestFlatStyling
ui.applyStyle( "maximumThumbSize: 1,2" ); ui.applyStyle( "maximumThumbSize: 1,2" );
ui.applyStyle( "allowsAbsolutePositioning: true" ); ui.applyStyle( "allowsAbsolutePositioning: true" );
ui.applyStyle( "minimumButtonSize: 1,2" );
ui.applyStyle( "trackInsets: 1,2,3,4" ); ui.applyStyle( "trackInsets: 1,2,3,4" );
ui.applyStyle( "thumbInsets: 1,2,3,4" ); ui.applyStyle( "thumbInsets: 1,2,3,4" );
ui.applyStyle( "trackArc: 5" ); ui.applyStyle( "trackArc: 5" );

View File

@@ -217,8 +217,8 @@ public class FlatTaskPaneUI
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
// scale chevron size // scale chevron size
float cw = scale( 6f ); float cw = scale( 7f );
float ch = scale( 3f ); float ch = scale( 3.5f );
// create arrow shape // create arrow shape
int direction = group.isCollapsed() ? SwingConstants.SOUTH : SwingConstants.NORTH; int direction = group.isCollapsed() ? SwingConstants.SOUTH : SwingConstants.NORTH;
@@ -237,9 +237,9 @@ public class FlatTaskPaneUI
// paint // paint
g2.translate( cx, cy ); g2.translate( cx, cy );
g2.draw( arrowShape ); FlatUIUtils.drawShapePure( g2, arrowShape );
g2.translate( 0, offset ); g2.translate( 0, offset );
g2.draw( arrowShape ); FlatUIUtils.drawShapePure( g2, arrowShape );
g2.translate( -cx, -(cy + offset) ); g2.translate( -cx, -(cy + offset) );
} }

View File

@@ -862,6 +862,7 @@ ScrollBar.hoverThumbColor #6e767a HSL 200 5 45 com.formdev.flatlaf.u
ScrollBar.hoverThumbWithTrack false ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(4%) 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.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.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedButtonBackground #54595c HSL 203 5 35 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%) 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%) ScrollBar.pressedThumbColor #7a8387 HSL 198 5 50 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15%)

View File

@@ -867,6 +867,7 @@ ScrollBar.hoverThumbColor #c3c3c3 HSL 0 0 76 com.formdev.flatlaf.u
ScrollBar.hoverThumbWithTrack false ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #ededed HSL 0 0 93 com.formdev.flatlaf.util.DerivedColor [UI] darken(3%) 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.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.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedButtonBackground #d9d9d9 HSL 0 0 85 com.formdev.flatlaf.util.DerivedColor [UI] darken(10%) 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%) ScrollBar.pressedThumbColor #a9a9a9 HSL 0 0 66 com.formdev.flatlaf.util.DerivedColor [UI] darken(20%)

View File

@@ -874,6 +874,7 @@ ScrollBar.hoverThumbColor #ff0000 HSL 0 100 50 javax.swing.plaf.Colo
ScrollBar.hoverThumbWithTrack false ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI] ScrollBar.hoverTrackColor #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [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.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedThumbWithTrack false ScrollBar.pressedThumbWithTrack false
ScrollBar.showButtons false ScrollBar.showButtons false

View File

@@ -673,7 +673,7 @@ public class FlatPaintingTest
panel5.add(arrowSizeLabel, "cell 0 2"); panel5.add(arrowSizeLabel, "cell 0 2");
//---- arrowSizeSpinner ---- //---- arrowSizeSpinner ----
arrowSizeSpinner.setModel(new SpinnerNumberModel(8, 2, null, 1)); arrowSizeSpinner.setModel(new SpinnerNumberModel(9, 2, null, 1));
arrowSizeSpinner.addChangeListener(e -> arrowSizeChanged()); arrowSizeSpinner.addChangeListener(e -> arrowSizeChanged());
panel5.add(arrowSizeSpinner, "cell 1 2"); panel5.add(arrowSizeSpinner, "cell 1 2");

View File

@@ -564,7 +564,7 @@ new FormModel {
name: "arrowSizeSpinner" name: "arrowSizeSpinner"
"model": new javax.swing.SpinnerNumberModel { "model": new javax.swing.SpinnerNumberModel {
minimum: 2 minimum: 2
value: 8 value: 9
} }
auxiliary() { auxiliary() {
"JavaCodeGenerator.variableLocal": false "JavaCodeGenerator.variableLocal": false

View File

@@ -658,6 +658,7 @@ ScrollBar.hoverThumbColor
ScrollBar.hoverThumbWithTrack ScrollBar.hoverThumbWithTrack
ScrollBar.hoverTrackColor ScrollBar.hoverTrackColor
ScrollBar.maximumThumbSize ScrollBar.maximumThumbSize
ScrollBar.minimumButtonSize
ScrollBar.minimumThumbSize ScrollBar.minimumThumbSize
ScrollBar.pressedButtonBackground ScrollBar.pressedButtonBackground
ScrollBar.pressedThumbColor ScrollBar.pressedThumbColor