All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.swm.commons.mobile.client.widgets.scroll.ScrollPanelWithScrollbar Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2011 SWM Services GmbH.
 * 
 * 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 de.swm.commons.mobile.client.widgets.scroll;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.event.dom.client.MouseWheelHandler;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import de.swm.commons.mobile.client.SWMMobile;
import de.swm.commons.mobile.client.base.PanelBase;
import de.swm.commons.mobile.client.event.*;
import de.swm.commons.mobile.client.utils.Utils;
import de.swm.commons.mobile.client.widgets.ScrollBar;


/**
 * Scroll panel - has the ability to keep the {@link de.swm.commons.mobile.client.widgets.itf.IHeaderPanel} implementations always on the top.
 */
public class ScrollPanelWithScrollbar extends PanelBase implements HasWidgets, DragEventsHandler, SwipeEventsHandler, IScrollPanel {

	private static final int TIME_FACTOR = 3000;
	private static final double DISTANCE_FACTOR = 0.25;
	public static final int DEFAULT_TRANSITION_DURATION = 500;
	private static final int OFFSET = 2;
	private boolean myHasTextBox = false;
	private IScrollMonitor scrollMonitor;
	private final ScrollBar scrollBar;

	private boolean showScrollBar = true;

	/**
	 * Default constructor.
	 */
	public ScrollPanelWithScrollbar() {
		setStyleName(SWMMobile.getTheme().getMGWTCssBundle().getScrollPanelCss().scrollPanel());
		this.scrollBar = new ScrollBar();
	}


	public void setHasTextBox(boolean hasTextBox) {
		myHasTextBox = hasTextBox && SWMMobile.getOsDetection().isAndroid();
	}


	public boolean getHasTextBox() {
		return myHasTextBox;
	}


	@Override
	public void onLoad() {
		boolean isDesktop = SWMMobile.getOsDetection().isDesktop();

		DragController.get().addDragEventsHandler(this);
		DragController.get().addSwipeEventsHandler(this);

		if (isDesktop) {
			addMouseWheelHandler();
		}
	}


	@Override
	public void onUnload() {
		DragController.get().removeDragEventsHandler(this);
		DragController.get().removeSwipeEventHandler(this);
	}


	@Override
	public Widget getWidget() {
		return myFlowPanel.getWidget(1);
	}


	/**
	 * Scrolls to the default position.
	 */

	private void addMouseWheelHandler() {
		this.addDomHandler(new MouseWheelHandler() {
			@Override
			public void onMouseWheel(MouseWheelEvent mouseWheelEvent) {
				int newScrollPosition = getScrollPosition() - mouseWheelEvent.getDeltaY() * 10;

				if (newScrollPosition > 0) {
					newScrollPosition = 0;
				} else if (-newScrollPosition + Utils.getHeight(getElement()) > getWidget().getElement().getOffsetHeight()) {
					newScrollPosition = Utils.getHeight(getElement()) - getWidget().getElement().getOffsetHeight();
				}

				int screeHeight = Utils.getHeight(getElement());
				int widgetHeight = getWidget().getElement().getOffsetHeight();
				if (screeHeight > widgetHeight) {
					newScrollPosition = 0;
				}

				setScrollPosition(newScrollPosition);
			}
		}, MouseWheelEvent.getType());
	}

	public void reset() {
		Utils.setTransitionDuration(getWidget().getElement(), 0);
		Utils.setTranslateY(getWidget().getElement(), 0);
	}


	@Override
	public void setScrollMonitor(IScrollMonitor scrollMonitor) {
		this.scrollMonitor = scrollMonitor;
	}

	/**
	 * Scrolls to the top.
	 */
	public void setPostionToTop() {
		setScrollPosition(0, 0);
	}


	/**
	 * Scrolls to the button.
	 */
	public void setPositionToBottom() {
		setScrollPosition(this.getElement().getClientHeight() - this.getElement().getScrollHeight(), 0);
	}


	public void setScrollPosition(int pos) {
		setScrollPosition(pos, 0);
	}

	/**
	 * Sets the scroll position
	 *
	 * @param pos the y axis pos
	 */
	public void setScrollPosition(int pos, int transitionDuration) {
		Element element = getWidget().getElement();
		Utils.setTransitionDuration(element, transitionDuration);

		if (myHasTextBox) {
			setStyleTop(pos);
		} else {
			Utils.setTranslateY(element, pos);
		}


		if (showScrollBar) {
			int panelHeight = Utils.getHeight(this.getElement());
			int widgetHeight = getWidget().getElement().getOffsetHeight();
			this.scrollBar.renderScrollbar(widgetHeight, panelHeight, -pos, transitionDuration);
			this.scrollBar.fadeOut((int) transitionDuration + DEFAULT_TRANSITION_DURATION * 2);
		} else {
			this.scrollBar.hide();
		}
	}


	/**
	 * Returns the current scroll position.
	 *
	 * @return the position
	 */
	public int getScrollPosition() {
		if (myHasTextBox) {
			return getStyleTop();
		} else {
			Element element = getWidget().getElement();
			return Utils.getTranslateY(element);
		}
	}


	/**
	 * Returns the next scroll position
	 *
	 * @return then next scroll position
	 */
	public int getScrollToPosition() {
		if (myHasTextBox) {
			return getStyleTop();
		} else {
			Element element = getWidget().getElement();
			return Utils.getMatrixY(element);
		}
	}

	@Override
	public void setOffsetHeight(int offsetHeight) {

	}


	@Override
	public void onDragStart(DragEvent e) {
		if (scrollMonitor != null) {
			scrollMonitor.onScrollStart();
		}
		int matrix = getScrollToPosition();
		int current = getScrollPosition();
		if (current != matrix) { // scroll on going
			int diff = current - matrix;
			int offset = diff > OFFSET ? OFFSET : diff > -OFFSET ? diff : -OFFSET;
			setScrollPosition(matrix + offset, 0);
			DragController.get().suppressNextClick();
		}
		e.stopPropagation();
	}


	@Override
	public void onDragMove(DragEvent e) {
		Element widgetEle = getWidget().getElement();
		int panelHeight = Utils.getHeight(this.getElement());
		int widgetHeight = widgetEle.getOffsetHeight();
		int current = getScrollPosition();
		if (current > 0) {
			// exceed top boundary
			if (e.getOffsetY() > 0) { // resist scroll down.
				current += (int) (e.getOffsetY() / OFFSET); // need the cast for production mode.
			} else {
				current += e.getOffsetY() * OFFSET;
			}
		} else if (-current + panelHeight > widgetHeight) { // exceed bottom boundary
			if (e.getOffsetY() < 0) { // resist scroll up.
				current += (int) (e.getOffsetY() / OFFSET);
			} else {
				current += e.getOffsetY() * OFFSET;
			}
		} else {
			current += e.getOffsetY();
		}
		setScrollPosition(current, 0);
		e.stopPropagation();
	}

	@Override
	public void onDragEnd(DragEvent e) {
		Element widgetEle = getWidget().getElement();
		if (scrollMonitor != null) {
			scrollMonitor.onScrollEnd();
		}
		int current = getScrollPosition();
		if (current == 0) {
			return;
		}
		int panelHeight = Utils.getHeight(this.getElement());
		int widgetHeight = widgetEle.getOffsetHeight();
		if (current > 0 // exceed top boundary
				|| panelHeight > widgetHeight) {
			setScrollPosition(0, DEFAULT_TRANSITION_DURATION);
		} else if (-current + panelHeight > widgetHeight) { // exceed bottom boundary
			setScrollPosition(panelHeight - widgetHeight, DEFAULT_TRANSITION_DURATION);
		}
		e.stopPropagation();
	}


	@Override
	public void onSwipeVertical(SwipeEvent e) {
		Element widgetEle = getWidget().getElement();
		int panelHeight = Utils.getHeight(this.getElement());
		int widgetHeight = widgetEle.getOffsetHeight();
		long current = getScrollPosition();
		if ((current >= 0) // exceed top boundary
				|| (-current + panelHeight >= widgetHeight)) { // exceed bottom boundary
			return;
		}

		double speed = e.getSpeed();
		double timeFactor = TIME_FACTOR;
		long time = (long) Math.abs(speed * timeFactor);
		double dicstanceFactor = DISTANCE_FACTOR;
		long distance = (long) (speed * time * dicstanceFactor);
		// Utils.Console("speed " + speed + " time " + time + " distance " + distance + " current " + current);
		current += distance;
		// exceed top boundary?
		if (current > 0) {
			double timeAdj = 1 - (double) current / distance;
			time = (long) (time * timeAdj);
			current = 0;
		} else if (-current + panelHeight > widgetHeight) { // exceed bottom boundary
			long bottom = panelHeight - widgetHeight;
			double timeAdj = 1 - (double) (current - bottom) / distance;
			time = (long) (time * timeAdj);
			current = bottom;
		}
		setScrollPosition((int) current, (int) time);
	}


	@Override
	public void onSwipeHorizontal(SwipeEvent e) {
	}


	@Override
	public void add(Widget w) {
		assert myFlowPanel.getWidgetCount() == 0 : "Can only add one widget to ScrollPanel.";
		super.add(this.scrollBar);

		super.add(w);
		if (SWMMobile.getOsDetection().isIOs()) {
			Utils.setTranslateY(w.getElement(), 0); // anti-flickering on iOS.
		}
	}


	/**
	 * Returns the top style
	 *
	 * @return the top style in px
	 */
	private int getStyleTop() {
		Style style = getWidget().getElement().getStyle();
		String top = style.getTop();
		if (top.isEmpty()) {
			return 0;
		} else {
			return Integer.parseInt(top.replace("px", ""));
		}
	}


	/**
	 * Sets the top stype in pixel
	 *
	 * @param top the top syle
	 */

	private void setStyleTop(int top) {
		Style style = getWidget().getElement().getStyle();
		style.setTop(top, Unit.PX);
	}


	/**
	 * Indicates if the scroll bar should be shown or not.
	 *
	 * @return .
	 */
	public boolean isShowScrollBar() {
		return showScrollBar;
	}

	/**
	 * Indicates if the scroll bar should be shown or not.
	 *
	 * @param showScrollBar true if it should be shown, false if not.
	 */
	public void setShowScrollBar(boolean showScrollBar) {
		this.showScrollBar = showScrollBar;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy