/*
* Copyright 2011 Vancouver Ywebb Consulting Ltd
*
* 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.
* --------
* This class contains modified sources from gwtmobile-ui project.
*
* Copyright (c) 2010 Zhihua (Dennis) Jiang
*
* 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 next.i.mobile;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import next.i.mobile.DragEvent.Type;
import next.i.util.Utils;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.Node;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.Widget;
public abstract class DragController implements EventListener {
private List<DragEventsHandler> _dragEventHandlers = new ArrayList<DragEventsHandler>();
private List<SwipeEventsHandler> _swipeEventHandlers = new ArrayList<SwipeEventsHandler>();
protected DragEventsHandler _capturingDragEventsHandler = null;
protected SwipeEventsHandler _capturingSwipeEventsHandler = null;
protected Widget _source;
private boolean _isDown = false;
private boolean _suppressNextClick = false;
private long _lastDragTimeStamp = 0;
private Point _lastDragPos = new Point(0, 0);
private long _currDragTimeStamp = 0;
private Point _currDragPos = new Point(0, 0);
private JavaScriptObject _clickListener;
protected JavaScriptObject _dragStartListener;
protected JavaScriptObject _dragMoveListener;
protected JavaScriptObject _dragEndListener;
private Point _startDragPos = new Point(0, 0);
// private boolean _hasMoveStarted = false;
private DragEvent.Type movedirection;
private int movecounter = 0;
protected static DragController INSTANCE = GWT.create(DragController.class);
DragController() {
init();
}
public static DragController get() {
return INSTANCE;
}
protected void init() {
_source = RootLayoutPanel.get();
registerEvents();
}
public void addDragEventsHandler(DragEventsHandler dragHandler) {
_dragEventHandlers.add(dragHandler);
}
public void addSwipeEventsHandler(SwipeEventsHandler swipeHandler) {
_swipeEventHandlers.add(swipeHandler);
}
public void removeDragEventsHandler(DragEventsHandler dragHandler) {
_dragEventHandlers.remove(dragHandler);
}
public void removeSwipeEventHandler(SwipeEventsHandler swipeHandler) {
_swipeEventHandlers.remove(swipeHandler);
}
@Override
public void onBrowserEvent(Event e) {
String type = e.getType();
if (type.equals("click")) {
onClick(e);
}
}
private void onClick(Event e) {
if (_suppressNextClick) {
e.stopPropagation();
_suppressNextClick = false;
// XLog.info("click suppressed");
}
}
// TODO: May need an onPreStart event to indicate that mouse is down, but no
// movement yet,
// so onStart event can actually mean drag is indeed started.
protected void onStart(Event e, Point p) {
_isDown = true;
_suppressNextClick = false;
Date currentDateTime = new Date();
_lastDragTimeStamp = currentDateTime.getTime();
_currDragTimeStamp = _lastDragTimeStamp;
_lastDragPos.clone(p);
_currDragPos.clone(p);
_startDragPos.clone(p);
// XLog.info("onStart curr=" + (int) p.X() + " : " + (int) p.Y());
DragEvent dragEvent = new DragEvent(e, DragEvent.Type.Start, p.X(), p.Y(), p.X() - _currDragPos.X(), p.Y()
- _currDragPos.Y());
fireDragEvent(dragEvent);
}
protected void onMove(Event e, Point p) {
if (_isDown) {
if (p.equals(_currDragPos)) {
// XLog.info("NO movement onMove");
return;
}
_suppressNextClick = true;
if (movedirection == null && movecounter > 0) {
double vertDelta = Math.abs(_startDragPos.Y() - p.Y());
double horizDelta = Math.abs(_startDragPos.X() - p.X());
if (vertDelta > horizDelta) {
movedirection = Type.MoveVertical;
} else {
movedirection = Type.MoveHorizontal;
}
}
if (movedirection == null) {
movecounter++;
} else {
DragEvent dragEvent = new DragEvent(e, movedirection, p.X(), p.Y(), p.X() - _currDragPos.X(), p.Y()
- _currDragPos.Y());
fireDragEvent(dragEvent);
// XLog.info("moveDirection !!!! " + movedirection + " vertDelta=" +
// vertDelta + " horizDelta=" +horizDelta);
}
// XLog.info("onMove _lastDragPos=" + (int) _lastDragPos.X() + " : " +
// (int) _lastDragPos.Y() + " curr="
// + (int) p.X() + " : " + (int) p.Y());
DragEvent dragEvent = new DragEvent(e, Type.Move, p.X(), p.Y(), p.X() - _currDragPos.X(), p.Y()
- _currDragPos.Y());
fireDragEvent(dragEvent);
_lastDragPos.clone(_currDragPos);
_lastDragTimeStamp = _currDragTimeStamp;
_currDragPos.clone(p);
Date currentDateTime = new Date();
_currDragTimeStamp = currentDateTime.getTime();
}
}
protected void onEnd(Event e, Point p) {
movedirection = null;
movecounter = 0;
if (_isDown) {
_isDown = false;
DragEvent dragEvent = new DragEvent(e, DragEvent.Type.End, p.X(), p.Y(), p.X() - _currDragPos.X(), p.Y()
- _currDragPos.Y());
fireDragEvent(dragEvent);
double distanceX = p.X() - _lastDragPos.X();
double distanceY = p.Y() - _lastDragPos.Y();
double distance;
SwipeEvent.Type swipeType;
if (Math.abs(distanceX) > Math.abs(distanceY)) {
distance = distanceX;
swipeType = distance > 0 ? SwipeEvent.Type.HorizontalLeftRight : SwipeEvent.Type.HorizontalRightLeft;
} else {
distance = distanceY;
swipeType = distance > 0 ? SwipeEvent.Type.VerticalTopBottom : SwipeEvent.Type.VerticalBottomTop;
}
Date currentDateTime = new Date();
long time = currentDateTime.getTime() - _lastDragTimeStamp;
double speed = distance / time;
if (speed > 4) {
speed = 4;
} else if (speed < -4) {
speed = -4;
}
// XLog.info("onEnd, speed is " + speed);
if (Math.abs(speed) > 0.2) {
// XLog.info("onEnd, before swipeEvent .... speed is " + speed);
SwipeEvent swipeEvent = new SwipeEvent(e, swipeType, speed);
fireSwipeEvent(swipeEvent);
}
}
}
protected void fireDragEvent(DragEvent e) {
if (_capturingDragEventsHandler != null) {
e.dispatch(_capturingDragEventsHandler);
return;
}
EventTarget target = e.getNativeEvent().getEventTarget();
Node node = Node.as(target);
if (!Element.is(node)) {
node = node.getParentNode(); // Text node
}
if (Element.is(node)) {
Element ele = Element.as(target);
int count = 0;
while (ele != null) {
for (DragEventsHandler handler : _dragEventHandlers) {
if (ele.equals(handler.getElement())) {
e.dispatch(handler);
count++;
if (e.getStopPropagation() || count == _dragEventHandlers.size()) {
return;
}
}
}
ele = ele.getParentElement();
}
}
}
protected void fireSwipeEvent(SwipeEvent e) {
if (_capturingSwipeEventsHandler != null) {
e.dispatch(_capturingSwipeEventsHandler);
return;
}
if (_capturingDragEventsHandler != null) {
return;
}
EventTarget target = e.getNativeEvent().getEventTarget();
Node node = Node.as(target);
if (!Element.is(node)) {
// Text node
node = node.getParentNode();
}
if (Element.is(node)) {
Element ele = Element.as(target);
int count = 0;
while (ele != null) {
for (SwipeEventsHandler handler : _swipeEventHandlers) {
if (ele.equals(handler.getElement())) {
e.dispatch(handler);
count++;
if (e.getStopPropagation() || count == _swipeEventHandlers.size()) {
return;
}
}
}
ele = ele.getParentElement();
}
}
}
public void suppressNextClick() {
_suppressNextClick = true;
}
protected void registerEvents() {
if (_clickListener == null) {
_clickListener = Utils.addEventListener(_source.getElement(), "click", true, this);
}
}
protected void unregisterEvents() {
if (_clickListener != null) {
Utils.removeEventListener(_source.getElement(), "click", true, _clickListener);
_clickListener = null;
}
}
public void suspend() {
unregisterEvents();
// XLog.info("drag events suspended.");
}
public void resume() {
registerEvents();
// XLog.info("drag events resumed.");
}
public boolean captureDragEvents(DragEventsHandler cachingHandler) {
if (_capturingDragEventsHandler != null) {
return false;
}
_capturingDragEventsHandler = cachingHandler;
return true;
}
public boolean releaseDragCapture(DragEventsHandler cachingHandler) {
if (_capturingDragEventsHandler == null) {
return true;
}
if (_capturingDragEventsHandler != cachingHandler) {
return false;
}
_capturingDragEventsHandler = null;
return true;
}
public boolean captureSwipeEvents(SwipeEventsHandler cachingHandler) {
if (_capturingSwipeEventsHandler != null) {
return false;
}
_capturingSwipeEventsHandler = cachingHandler;
return true;
}
public boolean releaseSwipeCapture(SwipeEventsHandler cachingHandler) {
if (_capturingSwipeEventsHandler == null) {
return true;
}
if (_capturingSwipeEventsHandler != cachingHandler) {
return false;
}
_capturingSwipeEventsHandler = null;
return true;
}
}