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

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

View File

@@ -57,6 +57,7 @@ import com.formdev.flatlaf.util.UIScale;
*
* <!-- FlatScrollBarUI -->
*
* @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();
}

View File

@@ -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() {

View File

@@ -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.

View File

@@ -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

View File

@@ -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,

View File

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