package com.iambookmaster.client.iphone.common;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.ErrorEvent;
import com.google.gwt.event.dom.client.ErrorHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget;
public class IPhoneScrollPanel extends ScrollPanel {
public static final int DIRECTION_VERTICAL = 1;
public static final int DIRECTION_HORIZONTAL = 2;
public static final int DIRECTION_ALL = 3;
public static final int DIRECTION_NONE = 4;
public static final int SCROLL_DIRECTION_UP=0;
public static final int SCROLL_DIRECTION_DOWN=1;
public static final int SCROLL_DIRECTION_LEFT=2;
public static final int SCROLL_DIRECTION_RIGHT=3;
protected static final int RESIZE_LEVEL = 0;
private static final int MAX_DISTANCE = 40;
// private static final String CLICK_EVENT = "click";
private int[] startY;
private int[] startX;
private int outterHight;
private int innerHight;
private int outterWidth;
private int innerWidth;
private boolean delay;
private int direction=DIRECTION_VERTICAL;
private int scrollDelay;
// private boolean topArrow;
// private boolean bottomArrow;
private boolean start;
private IPhoneTouchListener listener;
private int scrollStep=5;
private ScrollTimer timer;
public boolean isEventsEnabled() {
return listener.isEventsEnabled();
}
public void setEventsEnabled(boolean eventsEnabled) {
listener.setEventsEnabled(eventsEnabled);
}
public boolean isTopArrow() {
return getScrollPosition()>0;
}
public void cleanEvent() {
start = false;
}
public boolean isBottomArrow() {
fillHight();
int max = innerHight-outterHight;
return getScrollPosition()<max;
}
public void setVisible(boolean visible) {
if (listener.isIE()) {
//for IE
getElement().getStyle().setOpacity(visible ? 1:0);
} else {
super.setVisible(visible);
}
}
public IPhoneScrollPanel() {
getElement().getStyle().setOverflow(Overflow.HIDDEN);
listener = new IPhoneTouchListener() {
private JavaScriptObject lastSource;
private JavaScriptObject lastTarget;
private Timer timer;
private int initialX;
private int initialY;
private int smaller;
private int bigger;
private void superEvent(JavaScriptObject source, String name, JavaScriptObject target) {
superEvent(lastSource, TOUCHSTART, startX, startY, target);
}
@Override
public boolean event(JavaScriptObject source, String name, int[] x,int[] y, JavaScriptObject target) {
if (TOUCHSTART.equals(name)) {
start=true;
startY = y;
startX = x;
initialX = x[0];
initialY = y[0];
smaller = 0;
bigger = 0;
fillHight();
if (delay) {
if (timer!=null) {
timer.cancel();
timer = null;
}
timer = new Timer() {
private int counter = 2;
@Override
public void run() {
counter--;
if (counter<=0) {
//no move events - it was a click
cancel();
timer = null;
if (hasHandler(lastTarget)) {
superEvent(lastSource, TOUCHSTART, lastTarget);
} else {
//scan all targets by coordinates
JavaScriptObject target = findClosestTarget(initialX,initialY,MAX_DISTANCE);
if (target == null) {
//not target - click to screen
onClick(initialX,initialY);
} else {
superEvent(lastSource, TOUCHSTART, target);
}
}
}
}
};
timer.scheduleRepeating(250);
lastSource = source;
lastTarget = target;
return false;
} else {
//no delay
superEvent(source, name, x, y, target);
}
} else if (TOUCHMOVE.equals(name)) {
if (start) {
if (timer!=null) {
timer.cancel();
}
if (x.length>1) {
//directions
if (startX.length>1) {
int diffOld = Math.abs(startX[0]-startX[1])+Math.abs(startY[0]-startY[1]);
int diffNew = Math.abs(x[0]-x[1])+Math.abs(y[0]-y[1]);
if (diffOld>diffNew) {
//smaller
if (smaller++ >= RESIZE_LEVEL) {
//do it
start = false;
makeSmaller();
}
} else if (diffOld<diffNew) {
//bigger
if (bigger++ >= RESIZE_LEVEL) {
//do it
start = false;
makeBigger();
}
}
}
} else {
switch (direction) {
case DIRECTION_VERTICAL:
if (Math.abs(x[0]-startX[0]) > Math.abs(y[0]-startY[0])) {
scrollHorizontal(x[0]-initialX);
} else {
scrollY(y[0]);
}
break;
case DIRECTION_HORIZONTAL:
if (Math.abs(x[0]-startX[0]) < Math.abs(y[0]-startY[0])) {
scrollVertical(y[0]-initialY);
} else {
scrollX(x[0]);
}
break;
case DIRECTION_NONE:
if (Math.abs(x[0]-startX[0]) < Math.abs(y[0]-startY[0])) {
scrollVertical(y[0]-initialY);
} else {
scrollHorizontal(x[0]-initialX);
}
break;
default:
scrollY(y[0]);
scrollX(x[0]);
break;
}
}
startY = y;
startX = x;
}
// } else if (CLICK_EVENT.equals(name)){
// onClick(x[0], y[0]);
} else {
//cancel
start = false;
}
return false;
}
private void scrollX(int x) {
if (x<startX[0]) {
//scroll right
if (innerWidth>outterWidth) {
int pos = getHorizontalScrollPosition();
startX[0] = startX[0]-x;
if (pos<innerWidth-outterWidth-startY[0]) {
scrollHorizontalTo(pos+startX[0]);
} else {
scrollHorizontalTo(innerWidth-outterWidth);
}
}
} else {
//scroll left
int pos = getHorizontalScrollPosition();
startX[0] = x - startX[0];
if (pos>startX[0]) {
scrollHorizontalTo(pos-startX[0]);
} else {
scrollHorizontalTo(0);
}
}
}
//support vertical scroll
private void scrollY(int y) {
if (y<startY[0]) {
//scroll down
if (innerHight>outterHight) {
int pos = getScrollPosition();
scrollVertical(startY[0]-y);
startY[0] = startY[0]-y;
if (pos<innerHight-outterHight-startY[0]) {
scrollTo(pos+startY[0]);
} else {
scrollTo(innerHight-outterHight);
}
}
} else {
//scroll up
int pos = getScrollPosition();
scrollVertical(startY[0]-y);
startY[0] = y - startY[0];
if (pos>startY[0]) {
scrollTo(pos-startY[0]);
} else {
scrollTo(0);
}
}
}
};
listener.addListener(getElement(),IPhoneTouchListener.TOUCHSTART,false);
listener.addListener(getElement(),IPhoneTouchListener.TOUCHMOVE,false);
listener.addListener(getElement(),IPhoneTouchListener.TOUCHEND,false);
// listener.addListener(getElement(),CLICK_EVENT,false);
// listener.addListener(getElement(),"touchEnd",false);
// listener.addListener(getElement(),"touchcancel",false);
}
protected void onClick(int initialX, int initialY) {
}
protected void makeBigger() {
}
protected void makeSmaller() {
}
protected void scrollVertical(int delta) {
}
public void scrollHorizontal(int delta) {
}
protected String getScrollImage(int direction) {
return null;
}
private void fillHight() {
outterHight = getOffsetHeight();
innerHight = DOM.getElementPropertyInt(getElement(), "scrollHeight");
outterWidth = getOffsetWidth();
innerWidth = DOM.getElementPropertyInt(getElement(), "scrollWidth");
}
private void scrollTo(int postion) {
setScrollPosition(postion);
ScrollEvent event = new IPhoneScrollEvent();
fireEvent(event);
}
protected void scrollHorizontalTo(int postion) {
setHorizontalScrollPosition(postion);
ScrollEvent event = new IPhoneScrollEvent();
fireEvent(event);
}
public void resetPosition() {
DeferredCommand.addCommand(new Command(){
public void execute() {
fillHight();
scrollTo(0);
}
});
}
public class IPhoneScrollEvent extends ScrollEvent {
}
public void scrollUp() {
cancelTimer();
int oldPos = getScrollPosition();
if (oldPos>0) {
int pos = oldPos - scrollStep;
if (pos<0) {
pos=0;
}
if (scrollDelay==0) {
scrollTo((pos/scrollStep)*scrollStep);
} else {
timer = new ScrollTimer(oldPos,pos,false);
}
}
}
public void scrollDown() {
cancelTimer();
fillHight();
int oldPos = getScrollPosition();
int max = innerHight-outterHight;
if (oldPos<max) {
int pos = oldPos + scrollStep;
if (pos>max) {
pos=max;
}
if (scrollDelay==0) {
scrollTo((pos/scrollStep)*scrollStep);
} else {
timer = new ScrollTimer(oldPos,pos,false);
}
}
}
@Override
public void setWidget(IsWidget w) {
if (timer != null) {
timer.cancel();
timer = null;
}
super.setWidget(w);
}
@Override
public void setWidget(Widget w) {
if (timer != null) {
timer.cancel();
timer = null;
}
super.setWidget(w);
}
public interface PublicWidget {
public void onAttach();
public void onDetach();
public Element getElement();
}
public class PublicImage extends Image implements PublicWidget {
public PublicImage(String url, LoadHandler loadHandler, ErrorHandler errorHandler) {
addLoadHandler(loadHandler);
addErrorHandler(errorHandler);
setUrl(url);
}
@Override
public void onAttach() {
super.onAttach();
}
@Override
public void onDetach() {
super.onDetach();
}
}
public class ScrollTimer extends Timer implements LoadHandler, ErrorHandler{
private int oldPos;
private int step;
private int newPos;
private boolean horizontal;
private String url;
private PublicWidget image;
private PublicWidget fleeper;
@Override
public void scheduleRepeating(int periodMillis) {
super.scheduleRepeating(periodMillis);
}
public ScrollTimer(int oldPos, int newPos, boolean horizontal) {
this.oldPos = oldPos;
this.newPos = newPos;
this.horizontal = horizontal;
step = (newPos - oldPos) / scrollDelay;
if (horizontal) {
if (oldPos<newPos) {
//right
url = getScrollImage(SCROLL_DIRECTION_RIGHT);
} else {
url = getScrollImage(SCROLL_DIRECTION_LEFT);
}
} else if (oldPos<newPos) {
//down
url = getScrollImage(SCROLL_DIRECTION_DOWN);
} else {
//up
url = getScrollImage(SCROLL_DIRECTION_UP);
}
if (url == null) {
scheduleRepeating(100);
} else {
//use this url
image = new PublicImage(url,this,this);
Element element = image.getElement();
Style style = element.getStyle();
style.setPosition(Position.ABSOLUTE);
// scrollImageNode = getElement().appendChild(element);
image.onAttach();
if (horizontal) {
style.setTop(0, Unit.PX);
if (oldPos<newPos) {
//right
style.setLeft(newPos, Unit.PX);
} else {
//left
style.setLeft(oldPos, Unit.PX);
}
} else if (oldPos<newPos) {
//down
style.setTop(newPos, Unit.PX);
style.setLeft(0, Unit.PX);
} else {
//right
style.setTop(newPos, Unit.PX);
style.setLeft(0, Unit.PX);
}
}
}
@Override
public void run() {
oldPos = oldPos + step;
if (step>0) {
if (oldPos>=newPos) {
cancelScroll();
return;
}
} else if (oldPos <= newPos) {
cancelScroll();
return;
}
if (horizontal) {
scrollHorizontalTo(oldPos);
} else {
scrollTo(oldPos);
}
}
public void cancelScroll() {
if (horizontal) {
scrollHorizontalTo(newPos);
} else {
scrollTo(newPos);
}
if (image != null) {
// image.onDetach();
image.getElement().removeFromParent();
// getElement().removeChild();
// image.removeFromParent();
}
cancel();
}
public void onError(ErrorEvent event) {
scheduleRepeating(100);
}
public void onLoad(LoadEvent event) {
scheduleRepeating(100);
}
}
private void cancelTimer() {
if (timer != null) {
timer.cancelScroll();
timer = null;
}
}
public boolean canScrollRight() {
return getHorizontalScrollPosition()>0;
}
public boolean scrollRight() {
cancelTimer();
int oldPos = getHorizontalScrollPosition();
if (oldPos>0) {
int pos = oldPos - scrollStep;
if (pos<0) {
pos=0;
}
if (scrollDelay==0) {
scrollHorizontalTo((pos/scrollStep)*scrollStep);
} else {
timer = new ScrollTimer(oldPos,pos,true);
}
return true;
} else {
return false;
}
}
public boolean canScrollLeft() {
fillHight();
int max = innerWidth-outterWidth;
return getHorizontalScrollPosition()<max;
}
public boolean scrollLeft() {
cancelTimer();
fillHight();
int oldPos = getHorizontalScrollPosition();
int max = innerWidth-outterWidth;
if (oldPos<max) {
int pos = oldPos + scrollStep;
if (pos>max) {
pos=max;
}
if (scrollDelay==0) {
scrollHorizontalTo((pos/scrollStep)*scrollStep);
} else {
timer = new ScrollTimer(oldPos,pos,true);
}
return true;
} else {
return false;
}
}
public void resetHandlers() {
cancelTimer();
listener.resetHandlers();
}
public HandlerRegistration addClickHandler(Widget widget, ClickHandler handler) {
return listener.addClickHandler(widget, handler);
}
public void setScrollDelay(boolean delay) {
this.delay = delay;
}
public boolean isSrollDelay() {
return delay;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
public void setScrollStep(int step) {
scrollStep = step;
}
public int getScrollDelay() {
return scrollDelay;
}
public void setScrollDelay(int scrollDelay) {
this.scrollDelay = scrollDelay;
}
@Override
protected void onDetach() {
cancelTimer();
super.onDetach();
}
// public boolean isScrollVisible() {
// System.out.println("offsetHeight");
// System.out.println(getElement().getClientHeight());
// System.out.println(getContainerElement().getClientHeight());
// System.out.println(getWidget().getElement().getClientHeight());
// System.out.println(DOM.getElementPropertyInt(getElement(), "scrollHeight"));
// return getElement().getOffsetHeight() < getContainerElement().getClientHeight();
// }
}