Slider: fixed painting issues:

- needle of directional thumb was not painted while dragging
- artifacts on HiDPI screen while dragging
- cut off focus indicator on HiDPI screen
This commit is contained in:
Karl Tauber
2020-11-19 18:59:24 +01:00
parent 1d3ce76b27
commit b5e7aa8553

View File

@@ -30,9 +30,11 @@ import java.awt.geom.RoundRectangle2D;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JSlider; import javax.swing.JSlider;
import javax.swing.LookAndFeel; import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicSliderUI; import javax.swing.plaf.basic.BasicSliderUI;
import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -286,74 +288,95 @@ debug*/
public static void paintThumb( Graphics g, JSlider slider, Rectangle thumbRect, boolean roundThumb, public static void paintThumb( Graphics g, JSlider slider, Rectangle thumbRect, boolean roundThumb,
Color thumbColor, Color thumbBorderColor, Color focusedColor, int focusWidth ) Color thumbColor, Color thumbBorderColor, Color focusedColor, int focusWidth )
{ {
int fw = UIScale.scale( focusWidth ); double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
int x = thumbRect.x + fw; if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
int y = thumbRect.y + fw; // paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
int width = thumbRect.width - fw - fw; HiDPIUtils.paintAtScale1x( (Graphics2D) g, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height,
int height = thumbRect.height - fw - fw; (g2d, x2, y2, width2, height2, scaleFactor) -> {
paintThumbImpl( g, slider, x2, y2, width2, height2,
roundThumb, thumbColor, thumbBorderColor, focusedColor,
(float) (focusWidth * scaleFactor) );
} );
return;
}
paintThumbImpl( g, slider, thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height,
roundThumb, thumbColor, thumbBorderColor, focusedColor, focusWidth );
}
private static void paintThumbImpl( Graphics g, JSlider slider, int x, int y, int width, int height,
boolean roundThumb, Color thumbColor, Color thumbBorderColor, Color focusedColor, float focusWidth )
{
int fw = Math.round( UIScale.scale( focusWidth ) );
int tx = x + fw;
int ty = y + fw;
int tw = width - fw - fw;
int th = height - fw - fw;
boolean focused = FlatUIUtils.isPermanentFocusOwner( slider ); boolean focused = FlatUIUtils.isPermanentFocusOwner( slider );
if( roundThumb ) { if( roundThumb ) {
// paint thumb focus border // paint thumb focus border
if( focused ) { if( focused ) {
g.setColor( focusedColor ); g.setColor( focusedColor );
((Graphics2D)g).fill( createRoundThumbShape( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height ) ); ((Graphics2D)g).fill( createRoundThumbShape( x, y, width, height ) );
} }
if( thumbBorderColor != null ) { if( thumbBorderColor != null ) {
// paint thumb border // paint thumb border
g.setColor( thumbBorderColor ); g.setColor( thumbBorderColor );
((Graphics2D)g).fill( createRoundThumbShape( x, y, width, height ) ); ((Graphics2D)g).fill( createRoundThumbShape( tx, ty, tw, th ) );
// paint thumb background // paint thumb background
float lw = UIScale.scale( 1f ); float lw = UIScale.scale( 1f );
g.setColor( thumbColor ); g.setColor( thumbColor );
((Graphics2D)g).fill( createRoundThumbShape( x + lw, y + lw, ((Graphics2D)g).fill( createRoundThumbShape( tx + lw, ty + lw,
width - lw - lw, height - lw - lw ) ); tw - lw - lw, th - lw - lw ) );
} else { } else {
// paint thumb background // paint thumb background
g.setColor( thumbColor ); g.setColor( thumbColor );
((Graphics2D)g).fill( createRoundThumbShape( x, y, width, height ) ); ((Graphics2D)g).fill( createRoundThumbShape( tx, ty, tw, th ) );
} }
} else { } else {
Graphics2D g2 = (Graphics2D) g.create(); Graphics2D g2 = (Graphics2D) g.create();
try { try {
g2.translate( thumbRect.x, thumbRect.y ); g2.translate( x, y );
if( slider.getOrientation() == JSlider.VERTICAL ) { if( slider.getOrientation() == JSlider.VERTICAL ) {
if( slider.getComponentOrientation().isLeftToRight() ) { if( slider.getComponentOrientation().isLeftToRight() ) {
g2.translate( 0, thumbRect.height ); g2.translate( 0, height );
g2.rotate( Math.toRadians( 270 ) ); g2.rotate( Math.toRadians( 270 ) );
} else { } else {
g2.translate( thumbRect.width, 0 ); g2.translate( width, 0 );
g2.rotate( Math.toRadians( 90 ) ); g2.rotate( Math.toRadians( 90 ) );
} }
int temp = width; // rotate thumb width/height
width = height; int temp = tw;
height = temp; tw = th;
th = temp;
} }
// paint thumb focus border // paint thumb focus border
if( focused ) { if( focused ) {
g2.setColor( focusedColor ); g2.setColor( focusedColor );
g2.fill( createDirectionalThumbShape( 0, 0, g2.fill( createDirectionalThumbShape( 0, 0,
width + fw + fw, height + fw + fw + (fw * 0.4142f), fw ) ); tw + fw + fw, th + fw + fw + (fw * 0.4142f), fw ) );
} }
if( thumbBorderColor != null ) { if( thumbBorderColor != null ) {
// paint thumb border // paint thumb border
g2.setColor( thumbBorderColor ); g2.setColor( thumbBorderColor );
g2.fill( createDirectionalThumbShape( fw, fw, width, height, 0 ) ); g2.fill( createDirectionalThumbShape( fw, fw, tw, th, 0 ) );
// paint thumb background // paint thumb background
float lw = UIScale.scale( 1f ); float lw = UIScale.scale( 1f );
g2.setColor( thumbColor ); g2.setColor( thumbColor );
g2.fill( createDirectionalThumbShape( fw + lw, fw + lw, g2.fill( createDirectionalThumbShape( fw + lw, fw + lw,
width - lw - lw, height - lw - lw - (lw * 0.4142f), 0 ) ); tw - lw - lw, th - lw - lw - (lw * 0.4142f), 0 ) );
} else { } else {
// paint thumb background // paint thumb background
g2.setColor( thumbColor ); g2.setColor( thumbColor );
g2.fill( createDirectionalThumbShape( fw, fw, width, height, 0 ) ); g2.fill( createDirectionalThumbShape( fw, fw, tw, th, 0 ) );
} }
} finally { } finally {
g2.dispose(); g2.dispose();
@@ -404,6 +427,32 @@ debug*/
return !slider.getPaintTicks() && !slider.getPaintLabels(); return !slider.getPaintTicks() && !slider.getPaintLabels();
} }
@Override
public void setThumbLocation( int x, int y ) {
if( !isRoundThumb() ) {
// the needle of the directional thumb is painted outside of thumbRect
// --> must increase repaint rectangle
// set new thumb location and compute union of old and new thumb bounds
Rectangle r = new Rectangle( thumbRect );
thumbRect.setLocation( x, y );
SwingUtilities.computeUnion( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height, r );
// increase union rectangle for repaint
int extra = (int) Math.ceil( UIScale.scale( focusWidth ) * 0.4142f );
if( slider.getOrientation() == JSlider.HORIZONTAL )
r.height += extra;
else {
r.width += extra;
if( !slider.getComponentOrientation().isLeftToRight() )
r.x -= extra;
}
slider.repaint( r );
} else
super.setThumbLocation( x, y );
}
//---- class FlatTrackListener -------------------------------------------- //---- class FlatTrackListener --------------------------------------------
protected class FlatTrackListener protected class FlatTrackListener