/*
* 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 org.jboss.errai.ui.cordova.events.touch.pinch;
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 org.jboss.errai.ui.cordova.events.touch.AbstractRecognizer;
/**
* A PinchRecognizer tracks two finger on a screen that perform a zooming / pinching action
*
* @author Daniel Kurka
*
*/
public class PinchRecognizer extends AbstractRecognizer {
private final HasHandlers source;
private State state;
private Touch touchStart1;
private int touchCount;
private double distance;
private final OffsetProvider offsetProvider;
/**
* Construct a {@link PinchRecognizer}
*
* @param source the source to fire events on
* @param offsetProvider the offset provider
*/
public PinchRecognizer(HasHandlers source, OffsetProvider offsetProvider) {
if (source == null) {
throw new IllegalArgumentException("source can not be null");
}
if (offsetProvider == null) {
throw new IllegalArgumentException("offsetProvider can not be null");
}
this.source = source;
this.offsetProvider = offsetProvider;
state = State.READY;
}
@Override
public void onTouchStart(TouchStartEvent event) {
touchCount++;
switch (state) {
case READY:
touchStart1 = event.getTouches().get(0);
state = State.ONE_FINGER;
break;
case ONE_FINGER:
Touch touchStart2 = event.getTouches().get(1);
distance = (int) Math.sqrt(Math.pow(touchStart1.getPageX() - touchStart2.getPageX(), 2) + Math.pow(touchStart1.getPageY() - touchStart1.getPageY(), 2));
state = State.TWO_FINGER;
break;
default:
state = State.INVALID;
break;
}
}
@Override
public void onTouchMove(TouchMoveEvent event) {
switch (state) {
case TWO_FINGER:
Touch touch1 = event.getTouches().get(0);
Touch touch2 = event.getTouches().get(1);
int left = offsetProvider.getLeft();
int top = offsetProvider.getTop();
int x1 = touch1.getPageX() - left;
int y1 = touch1.getPageY() - top;
int x2 = touch2.getPageX() - left;
int y2 = touch2.getPageY() - top;
double newDistance = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));
int x = (x1 + x2) / 2;
int y = (y1 + y2) / 2;
source.fireEvent(new PinchEvent(x, y, distance / newDistance));
distance = newDistance;
break;
default:
state = State.INVALID;
break;
}
}
@Override
public void onTouchEnd(TouchEndEvent event) {
touchCount--;
if (touchCount <= 0) {
reset();
} else {
if (state == State.TWO_FINGER) {
state = State.ONE_FINGER;
} else {
if (touchCount == 2) {
state = State.TWO_FINGER;
}
}
}
}
@Override
public void onTouchCancel(TouchCancelEvent event) {
touchCount--;
if (touchCount <= 0) {
reset();
} else {
if (state == State.TWO_FINGER) {
state = State.ONE_FINGER;
} else {
if (touchCount == 2) {
state = State.TWO_FINGER;
}
}
}
}
private void reset() {
touchCount = 0;
state = State.READY;
}
}