/* * 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. */ package next.i.view; import next.i.XStyle; import next.i.mobile.DragController; import next.i.mobile.DragEvent; import next.i.mobile.DragEventsHandler; import next.i.mobile.SwipeEvent; import next.i.mobile.SwipeEventsHandler; import next.i.util.FxUtil; import next.i.util.Utils; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; /** * This view class accepts finger drag actions and can be scrolled horizontally * and vertically. */ public class XDragScrollView extends MPanelBase implements HasWidgets, DragEventsHandler, SwipeEventsHandler, IView { private boolean _hasTextBox = false; private Element widgetElement; private int panelWidth = -1; private int widgetWidth = -1; private int panelHeight = -1; private int widgetHeight = -1; public XDragScrollView() { setStyleName(XStyle.scrollPanel.name()); } public void setHasTextBox(boolean hasTextBox) { _hasTextBox = hasTextBox && Utils.isAndroid(); } public boolean getHasTextBox() { return _hasTextBox; } @Override public void onLoad() { DragController.get().addDragEventsHandler(this); DragController.get().addSwipeEventsHandler(this); } @Override public void onUnload() { DragController.get().removeDragEventsHandler(this); DragController.get().removeSwipeEventHandler(this); } @Override public Widget getWidget() { return _panel.getWidget(0); } public void reset() { FxUtil.setTransitionDuration(el(), 0); FxUtil.setTranslateX(el(), 0); FxUtil.setTranslateY(el(), 0); } public void setPostionToTop() { FxUtil.setTransitionDuration(el(), 0); FxUtil.setTranslateX(el(), 0); FxUtil.setTranslateY(el(), 0); } public void setPositionToBottom() { FxUtil.setTransitionDuration(el(), 0); //FxUtil.setTranslateX(el(), this.getElement().getClientWidth() - this.getElement().getScrollWidth()); FxUtil.setTranslateXY(el(), (this.getElement().getClientWidth() - this.getElement().getScrollWidth()), (this.getElement().getClientHeight() - this.getElement().getScrollHeight())); } public void setScrollPositionX(double pos) { if (_hasTextBox) { FxUtil.setStyleLeft(this, pos); } else { FxUtil.setTranslateX(el(), pos); } } public double getScrollPositionX() { if (_hasTextBox) { return FxUtil.getStyleLeft(this); } else { return FxUtil.getTranslateX(el()); } } public double getScrollToPositionX() { if (_hasTextBox) { return FxUtil.getStyleLeft(this); } else { return FxUtil.getMatrixX(el()); } } public void setScrollPositionY(double pos) { if (_hasTextBox) { FxUtil.setStyleTop(this, pos); } else { FxUtil.setTranslateY(el(), pos); } } public double getScrollPositionY() { if (_hasTextBox) { return FxUtil.getStyleTop(this); } else { return FxUtil.getTranslateY(el()); } } public double getScrollToPositionY() { if (_hasTextBox) { return FxUtil.getStyleTop(this); } else { return FxUtil.getMatrixY(el()); } } public void setScrollPositionXY(double posX, double posY) { if (_hasTextBox) { FxUtil.setStyleLeft(this, posX); FxUtil.setStyleTop(this, posY); } else { FxUtil.setTranslateXY(el(), posX, posY); } } @Override public void onDragStart(DragEvent e) { _lazyInit(); double matrixX = getScrollToPositionX(); double currX = getScrollPositionX(); double matrixY = getScrollToPositionY(); double currY = getScrollPositionY(); FxUtil.setTransitionDuration(el(), 0); if (currX != matrixX || currY != matrixY) { // scroll on going double diffX = currX - matrixX; double offsetX = diffX > 2 ? 2 : diffX > -2 ? diffX : -2; // setScrollPositionX(matrixX + offsetX); double diffY = currY - matrixY; double offsetY = diffY > 2 ? 2 : diffY > -2 ? diffY : -2; // setScrollPositionY(matrixY + offsetY); setScrollPositionXY(matrixX + offsetX, matrixY + offsetY); DragController.get().suppressNextClick(); } } @Override public void onDragMove(DragEvent e) { double currX = getScrollPositionX(); // exceed top boundary if (currX > 0) { // resist scroll down. if (e.OffsetX > 0) { currX += (int) (e.OffsetX / 2); } else { currX += e.OffsetX * 2; } // exceed bottom boundary } else if (-currX + panelWidth > widgetWidth) { // resist scroll up. if (e.OffsetX < 0) { currX += (int) (e.OffsetX / 2); } else { currX += e.OffsetX * 2; } } else { currX += e.OffsetX; } // XLog.info("current: " + current + ", e.OffsetX: " + e.OffsetX + // ", e.OffsetY: " + e.OffsetY + ", e.X: " + e.X // + ", e.Y: " + e.Y); // setScrollPositionX(currX); double currY = getScrollPositionY(); if (currY > 0) { // exceed top boundary if (e.OffsetY > 0) { // resist scroll down. currY += (int) (e.OffsetY / 2); // need the cast for production mode. } else { currY += e.OffsetY * 2; } } else if (-currY + panelHeight > widgetHeight) { // exceed bottom boundary if (e.OffsetY < 0) { // resist scroll up. currY += (int) (e.OffsetY / 2); } else { currY += e.OffsetY * 2; } } else { currY += e.OffsetY; } setScrollPositionXY(currX, currY); } @Override public void onDragEnd(DragEvent e) { double currX = getScrollPositionX(); double currY = getScrollPositionY(); if (currX == 0 || currY == 0) { return; } // exceed left boundary if (currX > 0 || panelWidth > widgetWidth) { FxUtil.setTransitionDuration(el(), 500); setScrollPositionXY(0, getScrollPositionY()); } else if (-currX + panelWidth > widgetWidth) { // exceed right boundary FxUtil.setTransitionDuration(el(), 500); setScrollPositionXY(panelWidth - widgetWidth, getScrollPositionY()); } // exceed top boundary if (currY > 0 || panelHeight > widgetHeight) { FxUtil.setTransitionDuration(el(), 500); setScrollPositionXY(getScrollPositionX(), 0); } else if (-currY + panelHeight > widgetHeight) { // exceed bottom boundary FxUtil.setTransitionDuration(el(), 500); setScrollPositionXY(getScrollPositionX(), panelHeight - widgetHeight); } } @Override public void onSwipeVertical(SwipeEvent e) { double currY = getScrollPositionY(); // exceed top boundary if ((currY >= 0) || (-currY + panelHeight >= widgetHeight)) { // exceed bottom boundary return; } double speed = e.getSpeed(); double timeFactor = 2800; long time = (long) Math.abs(speed * timeFactor); double dicstanceFactor = 0.24; long distance = (long) (speed * time * dicstanceFactor); // Utils.Console("speed " + speed + " time " + time + " distance " + // distance + " current " + current); currY += distance; if (currY > 0) { // exceed top boundary double timeAdj = 1 - (double) currY / distance; time = (long) (time * timeAdj); currY = 0; } else if (-currY + panelHeight > widgetHeight) { // exceed bottom boundary long bottom = panelHeight - widgetHeight; double timeAdj = 1 - (double) (currY - bottom) / distance; time = (long) (time * timeAdj); currY = bottom; } FxUtil.setTransitionDuration(el(), time); setScrollPositionXY(getScrollPositionX(), (int) currY); } @Override public void onSwipeHorizontal(SwipeEvent e) { double currX = getScrollPositionX(); // exceed left boundary if ((currX >= 0) || (-currX + panelWidth >= widgetWidth)) { // exceed right boundary return; } double speed = e.getSpeed(); double timeFactor = 2800; long time = (long) Math.abs(speed * timeFactor); double dicstanceFactor = 0.24; long distance = (long) (speed * time * dicstanceFactor); // Utils.Console("speed " + speed + " time " + time + " distance " + // distance + " currX " + currX); currX += distance; if (currX > 0) { // exceed left boundary double timeAdj = 1 - (double) currX / distance; time = (long) (time * timeAdj); currX = 0; } else if (-currX + panelWidth > widgetWidth) { // exceed right boundary long bottom = panelWidth - widgetWidth; double timeAdj = 1 - (double) (currX - bottom) / distance; time = (long) (time * timeAdj); currX = bottom; } FxUtil.setTransitionDuration(el(), time); setScrollPositionXY((int) currX, getScrollPositionY()); } @Override public void add(Widget w) { assert _panel.getWidgetCount() == 0 : "Can only add one widget to MScrollPanel."; super.add(w); } private Element el() { if (widgetElement == null) { widgetElement = getWidget().getElement(); } return widgetElement; } private void _lazyInit() { // lazy init. no reason to calculate each time in onDragMove if (panelWidth < 1) { panelWidth = FxUtil.getWidth(this.getElement()); } if (widgetWidth < 1) { widgetWidth = el().getOffsetWidth(); } panelHeight = FxUtil.getHeight(this.getElement()); widgetHeight = el().getOffsetHeight(); } @Override public void onDragMoveHorizontal(DragEvent e) { // Not implemented } @Override public void onDragMoveVertical(DragEvent e) { // Not implemented } }