diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedBorder.java index b47268e7..b681e729 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedBorder.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedBorder.java @@ -18,15 +18,15 @@ package com.formdev.flatlaf.util; import java.awt.Component; import java.awt.Graphics; +import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.border.Border; -import com.formdev.flatlaf.util.Animator.Interpolator; /** * Border that automatically animates painting on component value changes. *
* {@link #getValue(Component)} returns the value of the component. - * If the value changes, then {@link #paintBorderAnimated(Component, Graphics, int, int, int, int, float)} + * If the value changes, then {@link #paintAnimated(Component, Graphics2D, int, int, int, int, float)} * is invoked multiple times with animated value (from old value to new value). *
* Example for an animated border: @@ -35,7 +35,7 @@ import com.formdev.flatlaf.util.Animator.Interpolator; * implements AnimatedBorder * { * @Override - * public void paintBorderAnimated( Component c, Graphics g, int x, int y, int width, int height, float animatedValue ) { + * public void paintAnimated( Component c, Graphics2D g, int x, int y, int width, int height, float animatedValue ) { * int lh = UIScale.scale( 2 ); * * g.setColor( Color.blue ); @@ -65,199 +65,16 @@ import com.formdev.flatlaf.util.Animator.Interpolator; * A client property is set on the component to store the animation state. * * @author Karl Tauber - * @since 1.5 + * @since 2 */ public interface AnimatedBorder - extends Border + extends Border, AnimatedPainter { + /** + * Invokes {@link #paintWithAnimation(Component, Graphics, int, int, int, int)}. + */ @Override default void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { - AnimationSupport.paintBorder( this, c, g, x, y, width, height ); - } - - /** - * Paints the border for the given animated value. - * - * @param c the component that this border belongs to - * @param g the graphics context - * @param x the x coordinate of the border - * @param y the y coordinate of the border - * @param width the width coordinate of the border - * @param height the height coordinate of the border - * @param animatedValue the animated value, which is either equal to what {@link #getValue(Component)} - * returned, or somewhere between the previous value and the latest value - * that {@link #getValue(Component)} returned - */ - void paintBorderAnimated( Component c, Graphics g, int x, int y, int width, int height, float animatedValue ); - - /** - * Repaint the animated part of the border. - *
- * Useful to limit the repaint region. E.g. if only the bottom border is animated. - * If more than one border side is animated (e.g. bottom and right side), then it - * makes no sense to do separate repaints because the Swing repaint manager unions - * the regions and the whole component is repainted. - *
- * The default implementation repaints the whole component. - */ - default void repaintBorder( Component c, int x, int y, int width, int height ) { - c.repaint( x, y, width, height ); - } - - /** - * Gets the value of the component. - *
- * This can be any value and depends on the component. - * If the value changes, then this class animates from the old value to the new one. - *
- * For a text field this could be {@code 0} for not focused and {@code 1} for focused. - */ - float getValue( Component c ); - - /** - * Returns whether animation is enabled for this border (default is {@code true}). - */ - default boolean isAnimationEnabled() { - return true; - } - - /** - * Returns the duration of the animation in milliseconds (default is 150). - */ - default int getAnimationDuration() { - return 150; - } - - /** - * Returns the resolution of the animation in milliseconds (default is 10). - * Resolution is the amount of time between timing events. - */ - default int getAnimationResolution() { - return 10; - } - - /** - * Returns the interpolator for the animation. - * Default is {@link CubicBezierEasing#STANDARD_EASING}. - */ - default Interpolator getAnimationInterpolator() { - return CubicBezierEasing.STANDARD_EASING; - } - - /** - * Returns the client property key used to store the animation support. - */ - default Object getClientPropertyKey() { - return getClass(); - } - - //---- class AnimationSupport --------------------------------------------- - - /** - * Animation support class that stores the animation state and implements the animation. - */ - class AnimationSupport - { - private float startValue; - private float targetValue; - private float animatedValue; - private float fraction; - - private Animator animator; - - // last bounds of the border needed to repaint while animating - private int x; - private int y; - private int width; - private int height; - - public static void paintBorder( AnimatedBorder border, Component c, Graphics g, - int x, int y, int width, int height ) - { - if( !isAnimationEnabled( border, c ) ) { - // paint without animation if animation is disabled or - // component is not a JComponent and therefore does not support - // client properties, which are required to keep animation state - paintBorderImpl( border, c, g, x, y, width, height, null ); - return; - } - - JComponent jc = (JComponent) c; - Object key = border.getClientPropertyKey(); - AnimationSupport as = (AnimationSupport) jc.getClientProperty( key ); - if( as == null ) { - // painted first time --> do not animate, but remember current component value - as = new AnimationSupport(); - as.startValue = as.targetValue = as.animatedValue = border.getValue( c ); - jc.putClientProperty( key, as ); - } else { - // get component value - float value = border.getValue( c ); - - if( value != as.targetValue ) { - // value changed --> (re)start animation - - if( as.animator == null ) { - // create animator - AnimationSupport as2 = as; - as.animator = new Animator( border.getAnimationDuration(), fraction -> { - // check whether component was removed while animation is running - if( !c.isDisplayable() ) { - as2.animator.stop(); - return; - } - - // compute animated value - as2.animatedValue = as2.startValue + ((as2.targetValue - as2.startValue) * fraction); - as2.fraction = fraction; - - // repaint border - border.repaintBorder( c, as2.x, as2.y, as2.width, as2.height ); - }, () -> { - as2.startValue = as2.animatedValue = as2.targetValue; - as2.animator = null; - } ); - } - - if( as.animator.isRunning() ) { - // if animation is still running, restart it from the current - // animated value to the new target value with reduced duration - as.animator.cancel(); - int duration2 = (int) (border.getAnimationDuration() * as.fraction); - if( duration2 > 0 ) - as.animator.setDuration( duration2 ); - as.startValue = as.animatedValue; - } else { - // new animation - as.animator.setDuration( border.getAnimationDuration() ); - as.animator.setResolution( border.getAnimationResolution() ); - as.animator.setInterpolator( border.getAnimationInterpolator() ); - - as.animatedValue = as.startValue; - } - - as.targetValue = value; - as.animator.start(); - } - } - - as.x = x; - as.y = y; - as.width = width; - as.height = height; - - paintBorderImpl( border, c, g, x, y, width, height, as ); - } - - private static void paintBorderImpl( AnimatedBorder border, Component c, Graphics g, - int x, int y, int width, int height, AnimationSupport as ) - { - float value = (as != null) ? as.animatedValue : border.getValue( c ); - border.paintBorderAnimated( c, g, x, y, width, height, value ); - } - - private static boolean isAnimationEnabled( AnimatedBorder border, Component c ) { - return Animator.useAnimation() && border.isAnimationEnabled() && c instanceof JComponent; - } + paintWithAnimation( c, g, x, y, width, height ); } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedIcon.java index da0b0a1a..5c39d264 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedIcon.java @@ -18,9 +18,9 @@ package com.formdev.flatlaf.util; import java.awt.Component; import java.awt.Graphics; +import java.awt.Graphics2D; import javax.swing.Icon; import javax.swing.JComponent; -import com.formdev.flatlaf.util.Animator.Interpolator; /** * Icon that automatically animates painting on component value changes. @@ -65,15 +65,30 @@ import com.formdev.flatlaf.util.Animator.Interpolator; * @author Karl Tauber */ public interface AnimatedIcon - extends Icon + extends Icon, AnimatedPainter { + /** + * Invokes {@link #paintWithAnimation(Component, Graphics, int, int, int, int)}. + */ @Override - public default void paintIcon( Component c, Graphics g, int x, int y ) { - AnimationSupport.paintIcon( this, c, g, x, y ); + default void paintIcon( Component c, Graphics g, int x, int y ) { + paintWithAnimation( c, g, x, y, getIconWidth(), getIconHeight() ); } /** - * Paints the icon for the given animated value. + * Bridge method that is called from (new) superclass and delegates to + * {@link #paintIconAnimated(Component, Graphics, int, int, float)}. + * Necessary for API compatibility. + * + * @since 2 + */ + @Override + default void paintAnimated( Component c, Graphics2D g, int x, int y, int width, int height, float animatedValue ) { + paintIconAnimated( c, g, x, y, animatedValue ); + } + + /** + * Paints the icon for the given (animated) value. * * @param c the component that this icon belongs to * @param g the graphics context @@ -85,165 +100,19 @@ public interface AnimatedIcon */ void paintIconAnimated( Component c, Graphics g, int x, int y, float animatedValue ); - /** - * Gets the value of the component. - *
- * This can be any value and depends on the component. - * If the value changes, then this class animates from the old value to the new one. - *
- * For a toggle button this could be {@code 0} for off and {@code 1} for on. - */ - float getValue( Component c ); - - /** - * Returns whether animation is enabled for this icon (default is {@code true}). - */ - default boolean isAnimationEnabled() { - return true; - } - - /** - * Returns the duration of the animation in milliseconds (default is 150). - */ - default int getAnimationDuration() { - return 150; - } - - /** - * Returns the resolution of the animation in milliseconds (default is 10). - * Resolution is the amount of time between timing events. - */ - default int getAnimationResolution() { - return 10; - } - - /** - * Returns the interpolator for the animation. - * Default is {@link CubicBezierEasing#STANDARD_EASING}. - */ - default Interpolator getAnimationInterpolator() { - return CubicBezierEasing.STANDARD_EASING; - } - - /** - * Returns the client property key used to store the animation support. - */ - default Object getClientPropertyKey() { - return getClass(); - } - //---- class AnimationSupport --------------------------------------------- /** - * Animation support class that stores the animation state and implements the animation. + * Animation support. */ class AnimationSupport { - private float startValue; - private float targetValue; - private float animatedValue; - private float fraction; - - private Animator animator; - - // last x,y coordinates of the icon needed to repaint while animating - private int x; - private int y; - public static void paintIcon( AnimatedIcon icon, Component c, Graphics g, int x, int y ) { - if( !isAnimationEnabled( icon, c ) ) { - // paint without animation if animation is disabled or - // component is not a JComponent and therefore does not support - // client properties, which are required to keep animation state - paintIconImpl( icon, c, g, x, y, null ); - return; - } - - JComponent jc = (JComponent) c; - Object key = icon.getClientPropertyKey(); - AnimationSupport as = (AnimationSupport) jc.getClientProperty( key ); - if( as == null ) { - // painted first time --> do not animate, but remember current component value - as = new AnimationSupport(); - as.startValue = as.targetValue = as.animatedValue = icon.getValue( c ); - as.x = x; - as.y = y; - jc.putClientProperty( key, as ); - } else { - // get component value - float value = icon.getValue( c ); - - if( value != as.targetValue ) { - // value changed --> (re)start animation - - if( as.animator == null ) { - // create animator - AnimationSupport as2 = as; - as.animator = new Animator( icon.getAnimationDuration(), fraction -> { - // check whether component was removed while animation is running - if( !c.isDisplayable() ) { - as2.animator.stop(); - return; - } - - // compute animated value - as2.animatedValue = as2.startValue + ((as2.targetValue - as2.startValue) * fraction); - as2.fraction = fraction; - - // repaint icon - c.repaint( as2.x, as2.y, icon.getIconWidth(), icon.getIconHeight() ); - }, () -> { - as2.startValue = as2.animatedValue = as2.targetValue; - as2.animator = null; - } ); - } - - if( as.animator.isRunning() ) { - // if animation is still running, restart it from the current - // animated value to the new target value with reduced duration - as.animator.cancel(); - int duration2 = (int) (icon.getAnimationDuration() * as.fraction); - if( duration2 > 0 ) - as.animator.setDuration( duration2 ); - as.startValue = as.animatedValue; - } else { - // new animation - as.animator.setDuration( icon.getAnimationDuration() ); - as.animator.setResolution( icon.getAnimationResolution() ); - as.animator.setInterpolator( icon.getAnimationInterpolator() ); - - as.animatedValue = as.startValue; - } - - as.targetValue = value; - as.animator.start(); - } - - as.x = x; - as.y = y; - } - - paintIconImpl( icon, c, g, x, y, as ); - } - - private static void paintIconImpl( AnimatedIcon icon, Component c, Graphics g, int x, int y, AnimationSupport as ) { - float value = (as != null) ? as.animatedValue : icon.getValue( c ); - icon.paintIconAnimated( c, g, x, y, value ); - } - - private static boolean isAnimationEnabled( AnimatedIcon icon, Component c ) { - return Animator.useAnimation() && icon.isAnimationEnabled() && c instanceof JComponent; + AnimatedPainterSupport.paint( icon, c, g, x, y, icon.getIconWidth(), icon.getIconHeight() ); } public static void saveIconLocation( AnimatedIcon icon, Component c, int x, int y ) { - if( !isAnimationEnabled( icon, c ) ) - return; - - AnimationSupport as = (AnimationSupport) ((JComponent)c).getClientProperty( icon.getClientPropertyKey() ); - if( as != null ) { - as.x = x; - as.y = y; - } + AnimatedPainterSupport.saveLocation( icon, c, x, y ); } } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainter.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainter.java new file mode 100644 index 00000000..d85e76d2 --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainter.java @@ -0,0 +1,139 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.util; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import com.formdev.flatlaf.util.Animator.Interpolator; + +/** + * Painter that automatically animates painting on component value changes. + *
+ * {@link #getValue(Component)} returns the value of the component. + * If the value changes, then {@link #paintAnimated(Component, Graphics2D, int, int, int, int, float)} + * is invoked multiple times with animated value (from old value to new value). + *
+ * See {@link AnimatedBorder} or {@link AnimatedIcon} for examples. + *
+ * Animation works only if the component passed to {@link #paintWithAnimation(Component, Graphics, int, int, int, int)} + * is a instance of {@link JComponent}. + * A client property is set on the component to store the animation state. + * + * @author Karl Tauber + * @since 2 + */ +public interface AnimatedPainter +{ + /** + * Starts painting. + * Either invokes {@link #paintAnimated(Component, Graphics2D, int, int, int, int, float)} + * once to paint current value (see {@link #getValue(Component)}. Or if value has + * changed, compared to last painting, then it starts an animation and invokes + * {@link #paintAnimated(Component, Graphics2D, int, int, int, int, float)} + * multiple times with animated value (from old value to new value). + * + * @param c the component that this painter belongs to + * @param g the graphics context + * @param x the x coordinate of the paint area + * @param y the y coordinate of the paint area + * @param width the width of the paint area + * @param height the height of the paint area + */ + default void paintWithAnimation( Component c, Graphics g, int x, int y, int width, int height ) { + AnimatedPainterSupport.paint( this, c, g, x, y, width, height ); + } + + /** + * Paints the given (animated) value. + *
+ * Invoked from {@link #paintWithAnimation(Component, Graphics, int, int, int, int)}. + * + * @param c the component that this painter belongs to + * @param g the graphics context + * @param x the x coordinate of the paint area + * @param y the y coordinate of the paint area + * @param width the width of the paint area + * @param height the height of the paint area + * @param animatedValue the animated value, which is either equal to what {@link #getValue(Component)} + * returned, or somewhere between the previous value and the latest value + * that {@link #getValue(Component)} returned + */ + void paintAnimated( Component c, Graphics2D g, int x, int y, int width, int height, float animatedValue ); + + /** + * Invoked from animator to repaint an area. + *
+ * Useful to limit the repaint region. E.g. if only the bottom border is animated. + * If more than one border side is animated (e.g. bottom and right side), then it + * makes no sense to do separate repaints because the Swing repaint manager unions + * the regions and the whole component is repainted. + *
+ * The default implementation repaints the whole given area. + */ + default void repaintDuringAnimation( Component c, int x, int y, int width, int height ) { + c.repaint( x, y, width, height ); + } + + /** + * Gets the value of the component. + *
+ * This can be any value and depends on the component. + * If the value changes, then this class animates from the old value to the new one. + *
+ * For a toggle button this could be {@code 0} for off and {@code 1} for on. + */ + float getValue( Component c ); + + /** + * Returns whether animation is enabled for this painter (default is {@code true}). + */ + default boolean isAnimationEnabled() { + return true; + } + + /** + * Returns the duration of the animation in milliseconds (default is 150). + */ + default int getAnimationDuration() { + return 150; + } + + /** + * Returns the resolution of the animation in milliseconds (default is 10). + * Resolution is the amount of time between timing events. + */ + default int getAnimationResolution() { + return 10; + } + + /** + * Returns the interpolator for the animation. + * Default is {@link CubicBezierEasing#STANDARD_EASING}. + */ + default Interpolator getAnimationInterpolator() { + return CubicBezierEasing.STANDARD_EASING; + } + + /** + * Returns the client property key used to store the animation support. + */ + default Object getClientPropertyKey() { + return getClass(); + } +} diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainterSupport.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainterSupport.java new file mode 100644 index 00000000..e27ac2e4 --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainterSupport.java @@ -0,0 +1,144 @@ +/* + * Copyright 2021 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.util; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import javax.swing.JComponent; + +/** + * Animation support class that stores the animation state and implements the animation. + * + * @author Karl Tauber + * @since 2 + */ +class AnimatedPainterSupport +{ + private float startValue; + private float targetValue; + private float animatedValue; + private float fraction; + + private Animator animator; + + // last bounds of the paint area needed to repaint while animating + private int x; + private int y; + private int width; + private int height; + + static void paint( AnimatedPainter painter, Component c, Graphics g, + int x, int y, int width, int height ) + { + if( !isAnimationEnabled( painter, c ) ) { + // paint without animation if animation is disabled or + // component is not a JComponent and therefore does not support + // client properties, which are required to keep animation state + paintImpl( painter, c, g, x, y, width, height, null ); + return; + } + + JComponent jc = (JComponent) c; + Object key = painter.getClientPropertyKey(); + AnimatedPainterSupport as = (AnimatedPainterSupport) jc.getClientProperty( key ); + if( as == null ) { + // painted first time --> do not animate, but remember current component value + as = new AnimatedPainterSupport(); + as.startValue = as.targetValue = as.animatedValue = painter.getValue( c ); + jc.putClientProperty( key, as ); + } else { + // get component value + float value = painter.getValue( c ); + + if( value != as.targetValue ) { + // value changed --> (re)start animation + + if( as.animator == null ) { + // create animator + AnimatedPainterSupport as2 = as; + as.animator = new Animator( painter.getAnimationDuration(), fraction -> { + // check whether component was removed while animation is running + if( !c.isDisplayable() ) { + as2.animator.stop(); + return; + } + + // compute animated value + as2.animatedValue = as2.startValue + ((as2.targetValue - as2.startValue) * fraction); + as2.fraction = fraction; + + // repaint + painter.repaintDuringAnimation( c, as2.x, as2.y, as2.width, as2.height ); + }, () -> { + as2.startValue = as2.animatedValue = as2.targetValue; + as2.animator = null; + } ); + } + + if( as.animator.isRunning() ) { + // if animation is still running, restart it from the current + // animated value to the new target value with reduced duration + as.animator.cancel(); + int duration2 = (int) (painter.getAnimationDuration() * as.fraction); + if( duration2 > 0 ) + as.animator.setDuration( duration2 ); + as.startValue = as.animatedValue; + } else { + // new animation + as.animator.setDuration( painter.getAnimationDuration() ); + as.animator.setResolution( painter.getAnimationResolution() ); + as.animator.setInterpolator( painter.getAnimationInterpolator() ); + + as.animatedValue = as.startValue; + } + + as.targetValue = value; + as.animator.start(); + } + } + + as.x = x; + as.y = y; + as.width = width; + as.height = height; + + paintImpl( painter, c, g, x, y, width, height, as ); + } + + private static void paintImpl( AnimatedPainter painter, Component c, Graphics g, + int x, int y, int width, int height, AnimatedPainterSupport as ) + { + float value = (as != null) ? as.animatedValue : painter.getValue( c ); + painter.paintAnimated( c, (Graphics2D) g, x, y, width, height, value ); + } + + private static boolean isAnimationEnabled( AnimatedPainter painter, Component c ) { + return Animator.useAnimation() && painter.isAnimationEnabled() && c instanceof JComponent; + } + + static void saveLocation( AnimatedPainter painter, Component c, int x, int y ) { + if( !isAnimationEnabled( painter, c ) ) + return; + + AnimatedPainterSupport as = (AnimatedPainterSupport) ((JComponent)c).getClientProperty( painter.getClientPropertyKey() ); + if( as != null ) { + as.x = x; + as.y = y; + } + } +} diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedBorderTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedBorderTest.java index c24acd68..2169ce39 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedBorderTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedBorderTest.java @@ -140,19 +140,20 @@ public class FlatAnimatedBorderTest // javax.swing.border.AbstractBorder would be used @Override public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { - AnimationSupport.paintBorder( this, c, g, x, y, width, height ); + paintWithAnimation( c, g, x, y, width, height ); } @Override - public void paintBorderAnimated( Component c, Graphics g, int x, int y, int width, int height, float animatedValue ) { + public void paintAnimated( Component c, Graphics2D g, int x, int y, int width, int height, float animatedValue ) { FlatUIUtils.setRenderingHints( g ); // border width is 1 if not focused and 2 if focused float lw = UIScale.scale( 1 + animatedValue ); // paint border - g.setColor( ColorFunctions.mix( Color.red, Color.lightGray, animatedValue ) ); - FlatUIUtils.paintComponentBorder( (Graphics2D) g, x, y, width, height, 0, lw, 0 ); + Color color = ColorFunctions.mix( Color.red, Color.lightGray, animatedValue ); + FlatUIUtils.paintOutlinedComponent( g, x, y, width, height, 0, 0, 0, lw, 0, + null, color, null ); } @Override @@ -188,15 +189,15 @@ public class FlatAnimatedBorderTest // javax.swing.border.AbstractBorder would be used @Override public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { - AnimationSupport.paintBorder( this, c, g, x, y, width, height ); + paintWithAnimation( c, g, x, y, width, height ); } @Override - public void paintBorderAnimated( Component c, Graphics g, int x, int y, int width, int height, float animatedValue ) { + public void paintAnimated( Component c, Graphics2D g, int x, int y, int width, int height, float animatedValue ) { FlatUIUtils.setRenderingHints( g ); // use paintAtScale1x() for consistent line thickness when scaled - HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, width, height, + HiDPIUtils.paintAtScale1x( g, x, y, width, height, (g2d, x2, y2, width2, height2, scaleFactor) -> { float lh = (float) (UIScale.scale( 1f ) * scaleFactor); @@ -214,7 +215,7 @@ public class FlatAnimatedBorderTest } @Override - public void repaintBorder( Component c, int x, int y, int width, int height ) { + public void repaintDuringAnimation( Component c, int x, int y, int width, int height ) { // limit repaint to bottom border int lh = UIScale.scale( 2 ); c.repaint( x, y + height - lh, width, lh ); @@ -247,7 +248,7 @@ public class FlatAnimatedBorderTest implements AnimatedBorder { @Override - public void paintBorderAnimated( Component c, Graphics g, int x, int y, int width, int height, float animatedValue ) { + public void paintAnimated( Component c, Graphics2D g, int x, int y, int width, int height, float animatedValue ) { int lh = UIScale.scale( 2 ); g.setColor( Color.blue );