From 26d7008c045e65bf7f33bd19e5ab250dc372111b Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Mon, 22 Nov 2021 22:07:45 +0100 Subject: [PATCH] AnimatedPainter: support individual animation duration, resolution and interpolator depending on value(s) --- .../formdev/flatlaf/util/AnimatedPainter.java | 26 ++++++++++++++ .../flatlaf/util/AnimatedPainterSupport.java | 36 ++++++++++++++----- .../testing/FlatAnimatedBorderTest.java | 2 +- .../testing/FlatAnimatedBorderTest.jfd | 2 +- .../flatlaf/testing/FlatAnimatedIconTest.java | 2 +- .../flatlaf/testing/FlatAnimatedIconTest.jfd | 2 +- 6 files changed, 57 insertions(+), 13 deletions(-) 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 index 269e13b9..0ff83de7 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainter.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainter.java @@ -132,6 +132,32 @@ public interface AnimatedPainter return CubicBezierEasing.STANDARD_EASING; } + /** + * Returns the duration of the animation in milliseconds (default is 150) + * for the given value index and value. + */ + default int getAnimationDuration( int valueIndex, float value ) { + return getAnimationDuration(); + } + + /** + * Returns the resolution of the animation in milliseconds (default is 10) + * for the given value index and value. + * Resolution is the amount of time between timing events. + */ + default int getAnimationResolution( int valueIndex, float value ) { + return getAnimationResolution(); + } + + /** + * Returns the interpolator for the animation + * for the given value index and value. + * Default is {@link CubicBezierEasing#STANDARD_EASING}. + */ + default Interpolator getAnimationInterpolator( int valueIndex, float value ) { + return getAnimationInterpolator(); + } + /** * Returns the client property key used to store the animation support. */ 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 index 0c4d1126..1492c31f 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainterSupport.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/AnimatedPainterSupport.java @@ -29,6 +29,7 @@ import javax.swing.JComponent; */ class AnimatedPainterSupport { + private int valueIndex; private float startValue; private float targetValue; private float animatedValue; @@ -76,8 +77,6 @@ class AnimatedPainterSupport jc.putClientProperty( key, ass ); } - float[] animatedValues = new float[ass.length]; - for( int i = 0; i < ass.length; i++ ) { AnimatedPainterSupport as = ass[i]; float value = values[i]; @@ -85,15 +84,29 @@ class AnimatedPainterSupport if( as == null ) { // painted first time --> do not animate, but remember current component value as = new AnimatedPainterSupport(); + as.valueIndex = i; as.startValue = as.targetValue = as.animatedValue = value; ass[i] = as; } else if( value != as.targetValue ) { // value changed --> (re)start animation + int animationDuration = painter.getAnimationDuration( as.valueIndex, value ); + + // do not animate if animation duration (for current value) is zero + if( animationDuration <= 0 ) { + if( as.animator != null ) { + as.animator.cancel(); + as.animator = null; + } + as.startValue = as.targetValue = as.animatedValue = value; + as.fraction = 0; + continue; + } + if( as.animator == null ) { // create animator AnimatedPainterSupport as2 = as; - as.animator = new Animator( painter.getAnimationDuration(), fraction -> { + as.animator = new Animator( 1, fraction -> { // check whether component was removed while animation is running if( !c.isDisplayable() ) { as2.animator.stop(); @@ -116,19 +129,22 @@ class AnimatedPainterSupport // 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); + int duration2 = (int) (animationDuration * 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.animator.setDuration( animationDuration ); as.animatedValue = as.startValue; } + // update animator for new value + as.animator.setResolution( painter.getAnimationResolution( as.valueIndex, value ) ); + as.animator.setInterpolator( painter.getAnimationInterpolator( as.valueIndex, value ) ); + + // start animation as.targetValue = value; as.animator.start(); } @@ -137,10 +153,12 @@ class AnimatedPainterSupport as.y = y; as.width = width; as.height = height; - - animatedValues[i] = as.animatedValue; } + float[] animatedValues = new float[ass.length]; + for( int i = 0; i < ass.length; i++ ) + animatedValues[i] = ass[i].animatedValue; + painter.paintAnimated( c, (Graphics2D) g, x, y, width, height, animatedValues ); } 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 b4d6501b..14f94ea7 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 @@ -171,7 +171,7 @@ public class FlatAnimatedBorderTest add(durationLabel, "cell 0 11"); //---- durationField ---- - durationField.setModel(new SpinnerNumberModel(200, 100, null, 50)); + durationField.setModel(new SpinnerNumberModel(200, 0, null, 50)); add(durationField, "cell 0 11"); // JFormDesigner - End of component initialization //GEN-END:initComponents } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedBorderTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedBorderTest.jfd index 3a3e527e..4c32e5ed 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedBorderTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedBorderTest.jfd @@ -113,7 +113,7 @@ new FormModel { add( new FormComponent( "javax.swing.JSpinner" ) { name: "durationField" "model": new javax.swing.SpinnerNumberModel { - minimum: 100 + minimum: 0 stepSize: 50 value: 200 } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.java index b196d97a..49e80740 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.java @@ -145,7 +145,7 @@ public class FlatAnimatedIconTest add(durationLabel, "cell 0 7 3 1"); //---- durationField ---- - durationField.setModel(new SpinnerNumberModel(200, 100, null, 50)); + durationField.setModel(new SpinnerNumberModel(200, 0, null, 50)); add(durationField, "cell 0 7 3 1"); //---- buttonGroup1 ---- diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.jfd index dc62fa60..62a2ae32 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatAnimatedIconTest.jfd @@ -88,7 +88,7 @@ new FormModel { add( new FormComponent( "javax.swing.JSpinner" ) { name: "durationField" "model": new javax.swing.SpinnerNumberModel { - minimum: 100 + minimum: 0 stepSize: 50 value: 200 }