From b2cc69dd4959dc6aaddcd5ed1375bfe6eea142dd Mon Sep 17 00:00:00 2001 From: "maksim.pelevin" Date: Wed, 21 Aug 2019 12:56:01 +0300 Subject: [PATCH] IDEA-76396 fix bad animation when back/forward is pressed while scroll animation in progress GitOrigin-RevId: 4a613aa7932ce739b16e67c38dd01b5efc67aa04 --- .../util/ui/MouseWheelSmoothScroll.java | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/platform/platform-api/src/com/intellij/util/ui/MouseWheelSmoothScroll.java b/platform/platform-api/src/com/intellij/util/ui/MouseWheelSmoothScroll.java index 18491b180bd0..1ecc7457b1ee 100644 --- a/platform/platform-api/src/com/intellij/util/ui/MouseWheelSmoothScroll.java +++ b/platform/platform-api/src/com/intellij/util/ui/MouseWheelSmoothScroll.java @@ -16,7 +16,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.function.Consumer; -import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; import static java.lang.Math.*; @@ -58,8 +58,7 @@ public class MouseWheelSmoothScroll { int maximum = bar.getMaximum(); if (abs(delta) > 0.01) { // ignore small delta event animator.start(value, value + delta, bar::setValue, (v) -> { - if (minimum != bar.getMinimum() || maximum != bar.getMaximum()) return true; - return v <= minimum || v >= maximum - bar.getModel().getExtent(); + return v - bar.getValue() != 0 || minimum != bar.getMinimum() || maximum != bar.getMaximum(); }); } } @@ -98,8 +97,8 @@ public class MouseWheelSmoothScroll { private final Consumer BLACK_HOLE = (x) -> {}; private @NotNull Consumer myConsumer = BLACK_HOLE; - private final Function NEVER = (value) -> false; - private @NotNull Function myCancel = NEVER; + private final Predicate FALSE_PREDICATE = (value) -> false; + private @NotNull Predicate myShouldStop = FALSE_PREDICATE; private final Timer myTimer = new Timer(REFRESH_TIME, this); private final AverageDiff myAvgDiff = new AverageDiff<>(8); @@ -130,7 +129,7 @@ public class MouseWheelSmoothScroll { return rate; } - public final void start(int initValue, int targetValue, @NotNull Consumer consumer, @Nullable Function cancel) { + public final void start(int initValue, int targetValue, @NotNull Consumer consumer, @Nullable Predicate shouldStop) { if (getDuration() == 0) { stop(); consumer.accept(targetValue); @@ -141,30 +140,28 @@ public class MouseWheelSmoothScroll { double multiplierFactor = myAvgDiff.getAverage() <= HI_POLLING_TIME ? getTouchpadVelocityFactor() : getVelocityFactor(); myVelocity = multiplierFactor * (targetValue - initValue) / getDuration(); myConsumer = Objects.requireNonNull(consumer); - myCancel = cancel == null ? NEVER : cancel; + myShouldStop = shouldStop == null ? FALSE_PREDICATE : shouldStop; myCurrentValue = initValue; myTimer.start(); } @Override public final void actionPerformed(ActionEvent e) { - if (abs(myVelocity) >= 0.001) { - myCurrentValue += myVelocity * REFRESH_TIME; - int nextValue = (int)round(myCurrentValue); - myConsumer.accept(nextValue); - myVelocity *= exp(getVelocityDecayFactor() * REFRESH_TIME); - if (myCancel.apply(nextValue)) { - stop(); - } - } else { + if (abs(myVelocity) < 0.001 || myShouldStop.test((int)round(myCurrentValue))) { stop(); + return; } + + myCurrentValue += myVelocity * REFRESH_TIME; + int nextValue = (int)round(myCurrentValue); + myConsumer.accept(nextValue); + myVelocity *= exp(getVelocityDecayFactor() * REFRESH_TIME); } public final void stop() { myTimer.stop(); myConsumer = BLACK_HOLE; - myCancel = NEVER; + myShouldStop = FALSE_PREDICATE; myVelocity = 0.0; myAvgDiff.clear(); } @@ -199,7 +196,7 @@ public class MouseWheelSmoothScroll { } public double getAverage() { - if (myValues.isEmpty()) return Double.NaN; + if (myValues.size() < myCapacity) return Double.NaN; return myValues.stream().reduce(0.0, Double::sum) / myValues.size(); }