// Copyright 2012 Google Inc. All Rights Reserved. // // 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 // // http://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 org.eclipse.che.ide.util.dom; import elemental.events.MouseEvent; import elemental.util.Timer; /** * A helper that detects mouse movement pause. * <p/> * When mouse movement pause is detected, {@link Callback#onMouseMovePaused()} * is invoked once. Even if mouse stays still for a long time, * {@link Callback#onMouseMovePaused()} is only invoked once. Only after mouse * starts to move again, the detector resumes. */ public final class MouseMovePauseDetector { /** * An interface that receives callback from the {@link MouseMovePauseDetector} * when mouse move pause occur. */ public interface Callback { void onMouseMovePaused(); } private final Callback callback; private final Timer getRevisionWhenDragTimer; /** * If mouse did not move after DEFAULT_PAUSE_DURATION_MS, we consider move * paused. */ private static final int DEFAULT_PAUSE_DURATION_MS = 500; private static final int MOUSE_INVALID_POSITION = Integer.MIN_VALUE; private static final int MOUSE_MOVEMENT_THRESHOLD_SQUARED = 900; // (lastMouseX, lastMouseY) is the last mouse location. // It gets reset if mouse movement is over the threshold. private int lastMouseX = MOUSE_INVALID_POSITION; private int lastMouseY = MOUSE_INVALID_POSITION; private boolean enabled; public MouseMovePauseDetector(Callback callback) { this.callback = callback; getRevisionWhenDragTimer = new Timer() { @Override public void run() { mousePaused(); } }; } public void start() { enabled = true; lastMouseX = lastMouseY = MOUSE_INVALID_POSITION; } public void stop() { enabled = false; getRevisionWhenDragTimer.cancel(); } public void handleMouseMove(MouseEvent event) { if (!enabled) { return; } if (lastMouseX == MOUSE_INVALID_POSITION || isMoved(event.getClientX(), event.getClientY(), lastMouseX, lastMouseY)) { // Cancel current timer and start timeout. // Whenever the timer timeouts, mouse has paused long enough. getRevisionWhenDragTimer.cancel(); getRevisionWhenDragTimer.schedule(DEFAULT_PAUSE_DURATION_MS); lastMouseX = event.getClientX(); lastMouseY = event.getClientY(); } } private void mousePaused() { if (!enabled) { return; } callback.onMouseMovePaused(); } private boolean isMoved(int x1, int y1, int x2, int y2) { int deltaX = x1 - x2; int deltaY = y1 - y2; return deltaX * deltaX + deltaY * deltaY > MOUSE_MOVEMENT_THRESHOLD_SQUARED; } }