From 14667cc349f8c8d65966638b9fc2a0b272f6ec7c Mon Sep 17 00:00:00 2001 From: Henrik Paul Date: Wed, 2 Jul 2014 14:36:23 +0300 Subject: [PATCH] Move the scroll area, if pointer starts inside (#13334) Change-Id: I41549e2c85742fe7a1dfef14e84647609dbf9a71 --- .../selection/MultiSelectionRenderer.java | 94 ++++++++++++++++++- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java index aa063a34e7..0204a8862b 100644 --- a/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/ui/grid/selection/MultiSelectionRenderer.java @@ -151,17 +151,24 @@ public class MultiSelectionRenderer extends ComplexRenderer { */ private static final int GRADIENT_MIN_THRESHOLD_PX = 10; + /** + * The speed at which the gradient area recovers, once scrolling in that + * direction has started. + */ + private static final int SCROLL_AREA_REBOUND_PX_PER_SEC = 1; + private static final double SCROLL_AREA_REBOUND_PX_PER_MS = SCROLL_AREA_REBOUND_PX_PER_SEC / 1000.0d; + /** * The lowest y-coordinate on the {@link Event#getClientY() client} from * where we need to start scrolling towards the top. */ - private final int topBound; + private int topBound = -1; /** * The highest y-coordinate on the {@link Event#getClientY() client} * from where we need to scrolling towards the bottom. */ - private final int bottomBound; + private int bottomBound = -1; /** * true if the pointer is selecting, false if @@ -204,11 +211,19 @@ public class MultiSelectionRenderer extends ComplexRenderer { /** The logical index of the row that was most recently modified. */ private int logicalRow = -1; + /** @see #doScrollAreaChecks(int) */ + private int finalTopBound; + + /** @see #doScrollAreaChecks(int) */ + private int finalBottomBound; + + private boolean scrollAreaShouldRebound = false; + public AutoScrollerAndSelector(final int topBound, final int bottomBound, final int gradientArea, final boolean selectionPaint) { - this.topBound = topBound; - this.bottomBound = bottomBound; + this.finalTopBound = topBound; + this.finalBottomBound = bottomBound; this.gradientArea = gradientArea; this.selectionPaint = selectionPaint; } @@ -218,6 +233,8 @@ public class MultiSelectionRenderer extends ComplexRenderer { final double timeDiff = timestamp - prevTimestamp; prevTimestamp = timestamp; + reboundScrollArea(timeDiff); + pixelsToScroll += scrollSpeed * (timeDiff / 1000.0d); final int intPixelsToScroll = (int) pixelsToScroll; pixelsToScroll -= intPixelsToScroll; @@ -237,6 +254,28 @@ public class MultiSelectionRenderer extends ComplexRenderer { reschedule(); } + /** + * If the scroll are has been offset by the pointer starting out there, + * move it back a bit + */ + private void reboundScrollArea(double timeDiff) { + if (!scrollAreaShouldRebound) { + return; + } + + int reboundPx = (int) Math.ceil(SCROLL_AREA_REBOUND_PX_PER_MS + * timeDiff); + if (topBound < finalTopBound) { + topBound += reboundPx; + topBound = Math.min(topBound, finalTopBound); + updateScrollSpeed(pageY); + } else if (bottomBound > finalBottomBound) { + bottomBound -= reboundPx; + bottomBound = Math.max(bottomBound, finalBottomBound); + updateScrollSpeed(pageY); + } + } + private void updateScrollSpeed(final int pointerPageY) { final double ratio; @@ -282,10 +321,57 @@ public class MultiSelectionRenderer extends ComplexRenderer { @SuppressWarnings("hiding") public void updatePointerCoords(int pageX, int pageY) { + doScrollAreaChecks(pageY); updateScrollSpeed(pageY); this.pageX = pageX; this.pageY = pageY; } + + /** + * This method checks whether the first pointer event started in an area + * that would start scrolling immediately, and does some actions + * accordingly. + *

+ * If it is, that scroll area will be offset "beyond" the pointer (above + * if pointer is towards the top, otherwise below). + *

+ * *) This behavior will change in + * future patches (henrik paul 2.7.2014) + */ + private void doScrollAreaChecks(int pageY) { + /* + * The first run makes sure that neither scroll position is + * underneath the finger, but offset to either direction from + * underneath the pointer. + */ + if (topBound == -1) { + topBound = Math.min(finalTopBound, pageY); + bottomBound = Math.max(finalBottomBound, pageY); + } + + /* + * Subsequent runs make sure that the scroll area grows (but doesn't + * shrink) with the finger, but no further than the final bound. + */ + else { + int oldTopBound = topBound; + if (topBound < finalTopBound) { + topBound = Math.max(topBound, + Math.min(finalTopBound, pageY)); + } + + int oldBottomBound = bottomBound; + if (bottomBound > finalBottomBound) { + bottomBound = Math.min(bottomBound, + Math.max(finalBottomBound, pageY)); + } + + final boolean topDidNotMove = oldTopBound == topBound; + final boolean bottomDidNotMove = oldBottomBound == bottomBound; + final boolean wasVerticalMovement = pageY != this.pageY; + scrollAreaShouldRebound = (topDidNotMove && bottomDidNotMove && wasVerticalMovement); + } + } } /** -- 2.39.5