Package com.googlecode.mgwt.dom.client.recognizer.longtap

Source Code of com.googlecode.mgwt.dom.client.recognizer.longtap.LongTapRecognizer

/*
* Copyright 2012 Daniel Kurka
*
* 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 com.googlecode.mgwt.dom.client.recognizer.longtap;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Touch;
import com.google.gwt.event.dom.client.TouchCancelEvent;
import com.google.gwt.event.dom.client.TouchEndEvent;
import com.google.gwt.event.dom.client.TouchMoveEvent;
import com.google.gwt.event.dom.client.TouchStartEvent;
import com.google.gwt.event.shared.HasHandlers;

import com.googlecode.mgwt.collection.shared.CollectionFactory;
import com.googlecode.mgwt.collection.shared.LightArray;
import com.googlecode.mgwt.dom.client.event.touch.TouchCopy;
import com.googlecode.mgwt.dom.client.event.touch.TouchHandler;
import com.googlecode.mgwt.dom.client.recognizer.EventPropagator;
import com.googlecode.mgwt.dom.client.recognizer.TimerExecturGwtTimerImpl;
import com.googlecode.mgwt.dom.client.recognizer.TimerExecutor;
import com.googlecode.mgwt.dom.client.recognizer.TimerExecutor.CodeToRun;

/**
* This class can recognize long taps
*
* @author Daniel Kurka
*/
public class LongTapRecognizer implements TouchHandler {

  public static final int DEFAULT_WAIT_TIME_IN_MS = 1500;
  public static final int DEFAULT_MAX_DISTANCE = 15;

  protected enum State {
    INVALID, READY, FINGERS_DOWN, FINGERS_UP, WAITING
  };

  protected State state;
  private final HasHandlers source;
  private final int numberOfFingers;
  private final int time;

  private LightArray<TouchCopy> startPositions;
  private int touchCount;
  private final int distance;

  private TimerExecutor timerExecutor;

  private EventPropagator eventPropagator;

  private static EventPropagator DEFAULT_EVENT_PROPAGATOR;

  public LongTapRecognizer(HasHandlers source) {
    this(source, 1);
  }

  public LongTapRecognizer(HasHandlers source, int numberOfFingers) {
    this(source, numberOfFingers, DEFAULT_WAIT_TIME_IN_MS);
  }

  /**
   * Construct a LongTapRecognizer
   *
   * @param source the source on which to fire events on
   * @param numberOfFingers the number of fingers that should be detected
   * @param time the time the fingers need to touch
   */
  public LongTapRecognizer(HasHandlers source, int numberOfFingers, int time) {
    this(source, numberOfFingers, time, DEFAULT_MAX_DISTANCE);
  }

  /**
   * Construct a LongTapRecognizer
   *
   * @param source the source on which to fire events on
   * @param numberOfFingers the number of fingers that should be detected
   * @param time the time the fingers need to touch
   * @param maxDistance the maximum distance each finger is allowed to move
   */
  public LongTapRecognizer(HasHandlers source, int numberOfFingers, int time, int maxDistance) {

    if (source == null) {
      throw new IllegalArgumentException("source can not be null");
    }
    if (numberOfFingers < 1) {
      throw new IllegalArgumentException("numberOfFingers > 0");
    }

    if (time < 200) {
      throw new IllegalArgumentException("time > 200");
    }

    if (maxDistance < 0) {
      throw new IllegalArgumentException("maxDistance > 0");
    }

    this.source = source;
    this.numberOfFingers = numberOfFingers;
    this.time = time;
    this.distance = maxDistance;

    state = State.READY;
    startPositions = CollectionFactory.constructArray();
    touchCount = 0;
  }

  @Override
  public void onTouchStart(TouchStartEvent event) {

    JsArray<Touch> touches = event.getTouches();
    touchCount++;

    switch (state) {
      case INVALID:
        break;
      case READY:
        startPositions.push(TouchCopy.copy((touches.get(touchCount - 1))));
        state = State.FINGERS_DOWN;
        break;
      case FINGERS_DOWN:
        startPositions.push(TouchCopy.copy(touches.get(touchCount - 1)));
        break;
      case FINGERS_UP:
      default:
        state = State.INVALID;
        break;
    }

    if (touchCount == numberOfFingers) {
      state = State.WAITING;
      getTimerExecutor().execute(new CodeToRun() {

        @Override
        public void onExecution() {
          if (state != State.WAITING) {
            // something else happened forget it
            return;
          }

          getEventPropagator().fireEvent(source, new LongTapEvent(source, numberOfFingers, time, startPositions));
          reset();

        }
      }, time);
    }

    if (touchCount > numberOfFingers) {
      state = State.INVALID;
    }
  }

  @Override
  public void onTouchMove(TouchMoveEvent event) {
    switch (state) {
      case WAITING:
      case FINGERS_DOWN:
      case FINGERS_UP:
        // compare positions
        JsArray<Touch> currentTouches = event.getTouches();
        for (int i = 0; i < currentTouches.length(); i++) {
          Touch currentTouch = currentTouches.get(i);
          for (int j = 0; j < startPositions.length(); j++) {
            TouchCopy startTouch = startPositions.get(j);
            if (currentTouch.getIdentifier() == startTouch.getIdentifier()) {
              if (Math.abs(currentTouch.getPageX() - startTouch.getPageX()) > distance || Math.abs(currentTouch.getPageY() - startTouch.getPageY()) > distance) {
                state = State.INVALID;
                break;
              }
            }
            if (state == State.INVALID) {
              break;
            }
          }
        }

        break;

      default:
        state = State.INVALID;
        break;
    }
  }

  @Override
  public void onTouchEnd(TouchEndEvent event) {
    int currentTouches = event.getTouches().length();
    switch (state) {
      case WAITING:
        state = State.INVALID;
        break;

      case FINGERS_DOWN:
        state = State.FINGERS_UP;
        break;
      case FINGERS_UP:
        // are we ready?
        if (currentTouches == 0 && touchCount == numberOfFingers) {
          // fire and reset

          reset();
        }
        break;

      case INVALID:
      default:
        if (currentTouches == 0)
          reset();
        break;
    }
  }

  @Override
  public void onTouchCancel(TouchCancelEvent event) {
    state = State.INVALID;
    int currentTouches = event.getTouches().length();
    if (currentTouches == 0) {
      reset();
    }
  }

  protected void reset() {
    state = State.READY;
    touchCount = 0;
  }

  // Visible for testing
  TimerExecutor getTimerExecutor() {
    if (timerExecutor == null) {
      timerExecutor = new TimerExecturGwtTimerImpl();
    }
    return timerExecutor;
  }

  // Visible for testing
  EventPropagator getEventPropagator() {
    if (eventPropagator == null) {
      if (DEFAULT_EVENT_PROPAGATOR == null) {
        DEFAULT_EVENT_PROPAGATOR = GWT.create(EventPropagator.class);
      }
      eventPropagator = DEFAULT_EVENT_PROPAGATOR;
    }
    return eventPropagator;
  }
}
TOP

Related Classes of com.googlecode.mgwt.dom.client.recognizer.longtap.LongTapRecognizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.