mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-13 07:17:13 -06:00
FlatUIUtils: joined the 3 component painting methods (for focus border, border and background) into a single method paintOutlinedComponent()
- this allows optimized painting if focus color and border color are equal - avoids duplicate code - support focusWidthFraction for future animations
This commit is contained in:
@@ -103,9 +103,11 @@ public class FlatBorder
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
|
||||
float focusWidth = scale( (float) getFocusWidth( c ) );
|
||||
float focusInnerWidth = 0;
|
||||
float borderWidth = scale( (float) getBorderWidth( c ) );
|
||||
float arc = scale( (float) getArc( c ) );
|
||||
Color outlineColor = getOutlineColor( c );
|
||||
Color focusColor = null;
|
||||
|
||||
// paint outer border
|
||||
if( outlineColor != null || isFocused( c ) ) {
|
||||
@@ -114,15 +116,16 @@ public class FlatBorder
|
||||
: 0;
|
||||
|
||||
if( focusWidth > 0 || innerWidth > 0 ) {
|
||||
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
|
||||
FlatUIUtils.paintComponentOuterBorder( g2, x, y, width, height,
|
||||
focusWidth, borderWidth + scale( innerWidth ), arc );
|
||||
focusColor = (outlineColor != null) ? outlineColor : getFocusColor( c );
|
||||
focusInnerWidth = borderWidth + scale( innerWidth );
|
||||
}
|
||||
}
|
||||
|
||||
// paint border
|
||||
g2.setPaint( (outlineColor != null) ? outlineColor : getBorderColor( c ) );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, focusWidth, borderWidth, arc );
|
||||
Paint borderColor = (outlineColor != null) ? outlineColor : getBorderColor( c );
|
||||
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
|
||||
focusWidth, 1, focusInnerWidth, borderWidth, arc,
|
||||
focusColor, borderColor, null );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@@ -114,9 +114,10 @@ public class FlatButtonBorder
|
||||
width -= spacing.left + spacing.right;
|
||||
height -= spacing.top + spacing.bottom;
|
||||
|
||||
g2.setColor( (outlineColor != null) ? outlineColor : getFocusColor( c ) );
|
||||
// not using paintComponentOuterBorder() here because its round edges look too "thick"
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0, focusWidth, arc );
|
||||
Color color = (outlineColor != null) ? outlineColor : getFocusColor( c );
|
||||
// not using focus border painting of paintOutlinedComponent() here
|
||||
// because its round edges look too "thick"
|
||||
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height, 0, 0, 0, focusWidth, arc, null, color, null );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@@ -61,8 +61,8 @@ public class FlatLineBorder
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
try {
|
||||
FlatUIUtils.setRenderingHints( g2 );
|
||||
g2.setColor( getLineColor() );
|
||||
FlatUIUtils.paintComponentBorder( g2, x, y, width, height, 0f, scale( getLineThickness() ), 0f );
|
||||
FlatUIUtils.paintOutlinedComponent( g2, x, y, width, height,
|
||||
0, 0, 0, scale( getLineThickness() ), 0, null, getLineColor(), null );
|
||||
} finally {
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.Insets;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
@@ -351,104 +352,6 @@ public class FlatUIUtils
|
||||
: color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints an outer border, which is usually a focus border.
|
||||
* <p>
|
||||
* The outside bounds of the painted border are {@code x,y,width,height}.
|
||||
* The line thickness of the painted border is {@code focusWidth + lineWidth}.
|
||||
* The given arc diameter refers to the inner rectangle ({@code x,y,width,height} minus {@code focusWidth}).
|
||||
*
|
||||
* @see #paintComponentBorder
|
||||
* @see #paintComponentBackground
|
||||
*/
|
||||
public static void paintComponentOuterBorder( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
if( focusWidth + lineWidth == 0 )
|
||||
return; // nothing to paint
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintComponentOuterBorderImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), (float) (lineWidth * scaleFactor), (float) (arc * scaleFactor) );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintComponentOuterBorderImpl( g, x, y, width, height, focusWidth, lineWidth, arc );
|
||||
}
|
||||
|
||||
private static void paintComponentOuterBorderImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
float ow = focusWidth + lineWidth;
|
||||
float outerArc = arc + (focusWidth * 2);
|
||||
float innerArc = arc - (lineWidth * 2);
|
||||
|
||||
// reduce outer arc slightly for small arcs to make the curve slightly wider
|
||||
if( focusWidth > 0 && arc > 0 && arc < UIScale.scale( 10 ) )
|
||||
outerArc -= UIScale.scale( 2f );
|
||||
|
||||
Path2D path = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
path.append( createComponentRectangle( x, y, width, height, outerArc ), false );
|
||||
path.append( createComponentRectangle( x + ow, y + ow, width - (ow * 2), height - (ow * 2), innerArc ), false );
|
||||
g.fill( path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the border of a component as round rectangle.
|
||||
* <p>
|
||||
* The outside bounds of the painted border are
|
||||
* {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}.
|
||||
* The line thickness of the painted border is {@code lineWidth}.
|
||||
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
|
||||
*
|
||||
* @see #paintComponentOuterBorder
|
||||
* @see #paintComponentBackground
|
||||
*/
|
||||
public static void paintComponentBorder( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
if( lineWidth == 0 )
|
||||
return; // nothing to paint
|
||||
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintComponentBorderImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), (float) (lineWidth * scaleFactor), (float) (arc * scaleFactor) );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintComponentBorderImpl( g, x, y, width, height, focusWidth, lineWidth, arc );
|
||||
}
|
||||
|
||||
private static void paintComponentBorderImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float lineWidth, float arc )
|
||||
{
|
||||
float x1 = x + focusWidth;
|
||||
float y1 = y + focusWidth;
|
||||
float width1 = width - focusWidth * 2;
|
||||
float height1 = height - focusWidth * 2;
|
||||
float arc2 = arc - (lineWidth * 2);
|
||||
|
||||
Shape r1 = createComponentRectangle( x1, y1, width1, height1, arc );
|
||||
Shape r2 = createComponentRectangle(
|
||||
x1 + lineWidth, y1 + lineWidth,
|
||||
width1 - lineWidth * 2, height1 - lineWidth * 2, arc2 );
|
||||
|
||||
Path2D border = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
border.append( r1, false );
|
||||
border.append( r2, false );
|
||||
g.fill( border );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the background of a component with a round rectangle.
|
||||
* <p>
|
||||
@@ -456,32 +359,201 @@ public class FlatUIUtils
|
||||
* {@code x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)}.
|
||||
* The given arc diameter refers to the painted rectangle (and not to {@code x,y,width,height}).
|
||||
*
|
||||
* @see #paintComponentOuterBorder
|
||||
* @see #paintComponentBorder
|
||||
* @see #paintOutlinedComponent
|
||||
*/
|
||||
public static void paintComponentBackground( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float arc )
|
||||
{
|
||||
paintOutlinedComponent( g, x, y, width, height, focusWidth, 0, 0, 0, arc, null, null, g.getPaint() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints an outlined component with rounded corners, consisting of following parts:
|
||||
* <ul>
|
||||
* <li>an (optional) outer border, which is usually a focus indicator
|
||||
* <li>an (optional) component border
|
||||
* <li>the (optional) component background
|
||||
* </ul>
|
||||
* Each part is painted only if the corresponding part color is not {@code null}.
|
||||
* The parts are painted in this order:
|
||||
* <p>
|
||||
* <ol>
|
||||
* <li>background
|
||||
* <li>focus border
|
||||
* <li>border
|
||||
* </ol>
|
||||
*
|
||||
* <strong>Background</strong>:
|
||||
* The bounds of the filled round rectangle are
|
||||
* {@code [x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)]}.
|
||||
* The focus border and the border may paint over the background.
|
||||
* <p>
|
||||
*
|
||||
* <strong>Focus border</strong>:
|
||||
* The outside bounds of the painted focus border are {@code [x, y, width, height]}.
|
||||
* The thickness of the painted focus border is {@code (focusWidth * focusWidthFraction) + focusInnerWidth}.
|
||||
* The border may paint over the focus border if {@code focusInnerWidth > 0}.
|
||||
* <p>
|
||||
*
|
||||
* <strong>Border</strong>:
|
||||
* The outside bounds of the painted border are
|
||||
* {@code [x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)]}.
|
||||
* The thickness of the painted border is {@code lineWidth}.
|
||||
*
|
||||
* @param g the graphics context used for painting
|
||||
* @param x the x coordinate of the component
|
||||
* @param y the y coordinate of the component
|
||||
* @param width the width of the component
|
||||
* @param height the height of the component
|
||||
* @param focusWidth the width of the focus border, or {@code 0}
|
||||
* @param focusWidthFraction specified how much of the focus border is painted (in range 0 - 1);
|
||||
* can be used for animation;
|
||||
* the painted thickness of the focus border is {@code (focusWidth * focusWidthFraction) + focusInnerWidth}
|
||||
* @param focusInnerWidth the inner width of the focus border, or {@code 0};
|
||||
* if a border is painted then {@code focusInnerWidth} needs to be larger
|
||||
* than {@code lineWidth} to be not hidden by the border
|
||||
* @param borderWidth the width of the border, or {@code 0}
|
||||
* @param arc the arc diameter used for the outside shape of the component border;
|
||||
* the other needed arc diameters are computed from this arc diameter
|
||||
* @param focusColor the color of the focus border, or {@code null}
|
||||
* @param borderColor the color of the border, or {@code null}
|
||||
* @param background the background color of the component, or {@code null}
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static void paintOutlinedComponent( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float focusWidthFraction, float focusInnerWidth, float borderWidth, float arc,
|
||||
Paint focusColor, Paint borderColor, Paint background )
|
||||
{
|
||||
double systemScaleFactor = UIScale.getSystemScaleFactor( g );
|
||||
if( systemScaleFactor != 1 && systemScaleFactor != 2 ) {
|
||||
// paint at scale 1x to avoid clipping on right and bottom edges at 125%, 150% or 175%
|
||||
HiDPIUtils.paintAtScale1x( g, x, y, width, height,
|
||||
(g2d, x2, y2, width2, height2, scaleFactor) -> {
|
||||
paintComponentBackgroundImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), (float) (arc * scaleFactor) );
|
||||
paintOutlinedComponentImpl( g2d, x2, y2, width2, height2,
|
||||
(float) (focusWidth * scaleFactor), focusWidthFraction, (float) (focusInnerWidth * scaleFactor),
|
||||
(float) (borderWidth * scaleFactor), (float) (arc * scaleFactor),
|
||||
focusColor, borderColor, background );
|
||||
} );
|
||||
return;
|
||||
}
|
||||
|
||||
paintComponentBackgroundImpl( g, x, y, width, height, focusWidth, arc );
|
||||
paintOutlinedComponentImpl( g, x, y, width, height, focusWidth, focusWidthFraction, focusInnerWidth,
|
||||
borderWidth, arc, focusColor, borderColor, background );
|
||||
}
|
||||
|
||||
private static void paintComponentBackgroundImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float arc )
|
||||
private static void paintOutlinedComponentImpl( Graphics2D g, int x, int y, int width, int height,
|
||||
float focusWidth, float focusWidthFraction, float focusInnerWidth, float borderWidth, float arc,
|
||||
Paint focusColor, Paint borderColor, Paint background )
|
||||
{
|
||||
g.fill( createComponentRectangle(
|
||||
x + focusWidth, y + focusWidth,
|
||||
width - focusWidth * 2, height - focusWidth * 2, arc ) );
|
||||
// outside bounds of the border and the background
|
||||
float x1 = x + focusWidth;
|
||||
float y1 = y + focusWidth;
|
||||
float w1 = width - focusWidth * 2;
|
||||
float h1 = height - focusWidth * 2;
|
||||
|
||||
// fill background
|
||||
// bounds: x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)
|
||||
// arc diameter: arc
|
||||
if( background != null ) {
|
||||
g.setPaint( background );
|
||||
g.fill( createComponentRectangle( x1, y1, w1, h1, arc ) );
|
||||
}
|
||||
|
||||
// optimization: paint focus border and border in single operation if colors are equal
|
||||
if( borderColor != null && borderColor.equals( focusColor ) ) {
|
||||
borderColor = null;
|
||||
focusInnerWidth = Math.max( focusInnerWidth, borderWidth );
|
||||
}
|
||||
|
||||
// paint focus border
|
||||
// outer bounds: x, y, width, height
|
||||
// thickness: focusWidth + focusInnerWidth
|
||||
// outer arc diameter: arc + (focusWidth * 2)
|
||||
// inner arc diameter: arc - (focusInnerWidth * 2)
|
||||
float paintedFocusWidth = (focusWidth * focusWidthFraction) + focusInnerWidth;
|
||||
if( focusColor != null && paintedFocusWidth != 0 ) {
|
||||
// outside bounds of the focus border
|
||||
float inset = focusWidth - (focusWidth * focusWidthFraction);
|
||||
float x2 = x + inset;
|
||||
float y2 = y + inset;
|
||||
float w2 = width - (inset * 2);
|
||||
float h2 = height - (inset * 2);
|
||||
|
||||
float outerArc = arc + (focusWidth * 2);
|
||||
float innerArc = arc - (focusInnerWidth * 2);
|
||||
|
||||
// reduce outer arc slightly for small arcs to make the curve slightly wider
|
||||
if( focusWidth > 0 && arc > 0 && arc < UIScale.scale( 10 ) )
|
||||
outerArc -= UIScale.scale( 2f );
|
||||
|
||||
// consider focus width fraction
|
||||
if( focusWidthFraction != 1 )
|
||||
outerArc = arc + ((outerArc - arc) * focusWidthFraction);
|
||||
|
||||
g.setPaint( focusColor );
|
||||
paintOutline( g, x2, y2, w2, h2, paintedFocusWidth, outerArc, innerArc );
|
||||
}
|
||||
|
||||
// paint border
|
||||
// outer bounds: x + focusWidth, y + focusWidth, width - (focusWidth * 2), height - (focusWidth * 2)
|
||||
// thickness: borderWidth
|
||||
// outer arc diameter: arc
|
||||
// inner arc diameter: arc - (borderWidth * 2)
|
||||
if( borderColor != null && borderWidth != 0 ) {
|
||||
g.setPaint( borderColor );
|
||||
paintOutline( g, x1, y1, w1, h1, borderWidth, arc );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints an outline at the given bounds using the given line width.
|
||||
* Depending on the given arc, a rectangle, rounded rectangle or circle (if w == h) is painted.
|
||||
*
|
||||
* @param g the graphics context used for painting
|
||||
* @param x the x coordinate of the outline
|
||||
* @param y the y coordinate of the outline
|
||||
* @param w the width of the outline
|
||||
* @param h the height of the outline
|
||||
* @param lineWidth the width of the outline
|
||||
* @param arc the arc diameter used for the outside shape of the outline
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static void paintOutline( Graphics2D g, float x, float y, float w, float h,
|
||||
float lineWidth, float arc )
|
||||
{
|
||||
paintOutline( g, x, y, w, h, lineWidth, arc, arc - (lineWidth * 2) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints an outline at the given bounds using the given line width.
|
||||
* Depending on the given arc, a rectangle, rounded rectangle or circle (if w == h) is painted.
|
||||
*
|
||||
* @param g the graphics context used for painting
|
||||
* @param x the x coordinate of the outline
|
||||
* @param y the y coordinate of the outline
|
||||
* @param w the width of the outline
|
||||
* @param h the height of the outline
|
||||
* @param lineWidth the width of the outline
|
||||
* @param arc the arc diameter used for the outside shape of the outline
|
||||
* @param innerArc the arc diameter used for the inside shape of the outline
|
||||
*
|
||||
* @since 2
|
||||
*/
|
||||
public static void paintOutline( Graphics2D g, float x, float y, float w, float h,
|
||||
float lineWidth, float arc, float innerArc )
|
||||
{
|
||||
if( lineWidth == 0 || w <= 0 || h <= 0 )
|
||||
return;
|
||||
|
||||
float t = lineWidth;
|
||||
float t2x = t * 2;
|
||||
|
||||
Path2D border = new Path2D.Float( Path2D.WIND_EVEN_ODD );
|
||||
border.append( createComponentRectangle( x, y, w, h, arc ), false );
|
||||
border.append( createComponentRectangle( x + t, y + t, w - t2x, h - t2x, innerArc ), false );
|
||||
g.fill( border );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -492,6 +564,9 @@ public class FlatUIUtils
|
||||
if( arc <= 0 )
|
||||
return new Rectangle2D.Float( x, y, w, h );
|
||||
|
||||
if( w == h && arc >= w )
|
||||
return new Ellipse2D.Float( x, y, w, h );
|
||||
|
||||
arc = Math.min( arc, Math.min( w, h ) );
|
||||
return new RoundRectangle2D.Float( x, y, w, h, arc, arc );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user