Java tutorial
/* * 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 com.gwtm.ui.client.widgets; import java.beans.Beans; import java.util.ArrayList; import java.util.List; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.RepeatingCommand; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.event.logical.shared.HasValueChangeHandlers; import com.google.gwt.event.logical.shared.ResizeEvent; import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.EventListener; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.gwtm.ui.client.core.Utils; import com.gwtm.ui.client.core.widgets.CssFactory.BoxAlign; import com.gwtm.ui.client.core.widgets.CssFactory.BoxOrient; import com.gwtm.ui.client.core.widgets.CssFactory.BoxPack; import com.gwtm.ui.client.core.widgets.PanelBase; import com.gwtm.ui.client.events.DraggingEvent; import com.gwtm.ui.client.events.SwipeEvent; import com.gwtm.ui.client.themes.ThemeManager; public class SlidingPanel extends ScrollPanel implements ResizeHandler, HasValueChangeHandlers<Integer> { public enum IndicatorVisibility { none, alwaysvisible, autohide }; public enum IndicatorPosition { top, bottom }; public enum IndicatorType { dot, square, numeric, slidetitles }; private int defaultSlide = 1; private int currentSlide = 1; private BoxPanel innerPanel; private int slideWidth = 0; private int savedCurrentSlide = 1; private int savedScrollPosition = 0; private double swipeThreshold = 0.15; private boolean movingFlag = false; private IndicatorRow indicator = null; private IndicatorVisibility indicatorVisibility = IndicatorVisibility.autohide; private IndicatorPosition indicatorPosition = IndicatorPosition.bottom; private IndicatorType indicatorType = IndicatorType.dot; public SlidingPanel() { // set primary css class Utils.Widgets.setPrimaryCssClass(this, ThemeManager.getTheme().slidingpanel()); // set scroll direction of super scrollpanel setScrollDirection(ScrollDirection.Horizontal); // create the inner panel for slides and add it to super panel innerPanel = new BoxPanel(BoxOrient.horizontal, BoxPack.start, BoxAlign.start); innerPanel.setFullHeight(true); super.add(innerPanel); // know the available width before anything else, so this should give us without deferingcommands slideWidth = RootPanel.get().getOffsetWidth() - getElement().getAbsoluteLeft() - getElement().getAbsoluteRight(); // necessary to recalculate the width for the slides addResizeHandler(this); if (getIndicatorVisibility() != IndicatorVisibility.none) { indicator = new IndicatorRow(); //.createIndicator(indicatorVisibility, indicatorPosition, indicatorType); addRootWidget(indicator); } // define designtime message addDesignTimeMessage("Add Slides to the panel."); addDesignTimeMessage("Set the 'currentSlide' property to switch slide."); } @Override public void onLoad() { super.onLoad(); //refreshSlidesWidth(); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { if (getIndicatorVisibility() != IndicatorVisibility.none) { indicator.setActiveIndicator(getDefaultSlide()); indicator.show(); } refreshSlidesWidth(); } }); } public IndicatorVisibility getIndicatorVisibility() { return indicatorVisibility; } public void setIndicatorVisibility(IndicatorVisibility indicatorVisibility) { this.indicatorVisibility = indicatorVisibility; } public IndicatorPosition getIndicatorPosition() { return indicatorPosition; } public void setIndicatorPosition(IndicatorPosition indicatorPosition) { this.indicatorPosition = indicatorPosition; } public IndicatorType getIndicatorType() { return indicatorType; } public void setIndicatorType(IndicatorType indicatorType) { this.indicatorType = indicatorType; } public int getSlideCount() { return innerPanel.getWidgetCount(); } public void setDefaultSlide(int slide) { this.defaultSlide = slide; if (slide > 0 && slide < (getSlideCount() + 1)) { setCurrentSlide(slide); } } public int getDefaultSlide() { return this.defaultSlide; } public Slide getSlide(int index) { return (Slide) innerPanel.getWidget(index); } public int getSlideIndex(Slide slide) { return innerPanel.getWidgetIndex(slide); } @Override public void onDraggingStart(DraggingEvent e) { super.onDraggingStart(e); savedScrollPosition = (Utils.Fx.getTranslateX(this.getElement().getFirstChildElement()) * -1); savedCurrentSlide = calculateCurrentSlide(); if (getIndicatorVisibility() != IndicatorVisibility.none) indicator.show(); movingFlag = true; } @Override public void onSwipeHorizontal(SwipeEvent e) { // bypass swipe implementation from super.scrollpanel // this panel doesnt need it and actually it will break the sliding effect e.stopPropagation(); } @Override public void onDraggingEnd(DraggingEvent e) { int currentScroll = (Utils.Fx.getTranslateX(this.getElement().getFirstChildElement()) * -1); int currentSlide = calculateCurrentSlide(); int threshold = (int) (slideWidth * swipeThreshold); if (savedScrollPosition > currentScroll) { if (currentScroll < ((savedCurrentSlide * slideWidth - threshold) - slideWidth)) savedCurrentSlide = currentSlide; } else { if (currentScroll > ((savedCurrentSlide * slideWidth + threshold) - slideWidth)) savedCurrentSlide = currentSlide + 1; } Utils.Fx.setTransitionDuration(this.getElement().getFirstChildElement(), 500); setCurrentSlide(savedCurrentSlide); if (getIndicatorVisibility() == IndicatorVisibility.autohide) { Scheduler.get().scheduleFixedPeriod(new RepeatingCommand() { @Override public boolean execute() { if (!movingFlag) { indicator.hide(); return false; } return true; } }, 700); } movingFlag = false; } private int calculateCurrentSlide() { int currentScroll = (Utils.Fx.getTranslateX(this.getElement().getFirstChildElement()) * -1); int maxScroll = slideWidth * getSlideCount(); int currentSlide = ((currentScroll != 0) ? currentScroll * getSlideCount() / maxScroll : 0) + 1; return currentSlide; } public void setCurrentSlide(int x) { if (x > getSlideCount()) x = getSlideCount(); if (x > currentSlide) x = currentSlide + 1; else if (x < currentSlide) x = currentSlide - 1; currentSlide = x; Utils.Fx.setTranslateX(this.getElement().getFirstChildElement(), -((slideWidth * x) - slideWidth)); ValueChangeEvent.fire(this, x); indicator.setActiveIndicator(x); } public int getCurrentSlide() { return currentSlide; } @Override public void add(Widget w) { // assert (w instanceof Slide) : // "Can only add Slide widgets to SlidePanel."; // we can't assert because gwtdesign adds a Label by default if (Beans.isDesignTime()) { if (!(w instanceof Slide)) { addDesignTimeError("Can only add Slides to SlidePanel. Remove the " + Utils.getSimpleName(w.getClass()) + " widget."); return; } } // set the calculated width for each added slide panel w.setWidth(slideWidth + "px"); // add indicator if (getIndicatorVisibility() != IndicatorVisibility.none) indicator.addIndicator(); // add slide to inner panel innerPanel.add(w); } @Override public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Integer> handler) { return this.addHandler(handler, ValueChangeEvent.getType()); } @Override public void onResize(ResizeEvent event) { if (event != null && slideWidth == getElement().getOffsetWidth()) return; refreshSlidesWidth(); } protected void refreshSlidesWidth() { // update height for inner scroller Utils.Fx.setTransitionDuration(getIntPanel().getElement(), 0); // get new width if (getElement().getParentElement().getParentElement() != null) slideWidth = getElement().getParentElement().getParentElement().getOffsetWidth(); else slideWidth = getElement().getParentElement().getOffsetWidth(); // slideWidth = getParent().getParent().getOffsetWidth(); // update all slides width for (int i = 0; i < innerPanel.getWidgetCount(); i++) innerPanel.getWidget(i).setWidth(slideWidth + "px"); // set/reset the scroller position by setting it again setCurrentSlide(getCurrentSlide()); } class IndicatorRow extends PanelBase { static final String dotActive = "●"; static final String dotInactive = "○"; static final String squareActive = "▪"; static final String squareInactive = "▫"; IndicatorVisibility previousIndicatorVisibility = null; IndicatorPosition previousIndicatorPosition = null; IndicatorType previousIndicatorType = null; IndicatorRow() { //super(""); Utils.Widgets.setSecondaryCssClass(this, ThemeManager.getTheme().slideindicator()); configInficator(); } private void configInficator() { if (indicatorVisibility != previousIndicatorVisibility) { if (previousIndicatorVisibility != null) Utils.Widgets.removeCssClass(this, previousIndicatorVisibility.toString()); Utils.Widgets.addCssClass(this, indicatorVisibility.toString()); } if (indicatorPosition != previousIndicatorPosition) { if (previousIndicatorPosition != null) Utils.Widgets.removeCssClass(this, previousIndicatorPosition.toString()); Utils.Widgets.addCssClass(this, indicatorPosition.toString()); } if (indicatorType != previousIndicatorType) { if (previousIndicatorType != null) Utils.Widgets.removeCssClass(this, previousIndicatorType.toString()); Utils.Widgets.addCssClass(this, indicatorType.toString()); if (previousIndicatorType != null && previousIndicatorType == IndicatorType.slidetitles) { setIndicatorEvent(false); } else if (previousIndicatorType != null && indicatorType == IndicatorType.slidetitles) { setIndicatorEvent(true); } } previousIndicatorVisibility = indicatorVisibility; previousIndicatorPosition = indicatorPosition; previousIndicatorType = indicatorType; } List<JavaScriptObject> eventStack = new ArrayList<JavaScriptObject>(); void setIndicatorEvent(boolean addEvent) { for (int i = 0; i < getWidgetCount(); i++) if (addEvent) { eventStack.add(Utils.Eventing.addEventListener(getWidget(i).getElement(), "click", true, new IndicatorClickListener(i + 1))); } else { if (eventStack.size() == getWidgetCount()) Utils.Eventing.removeEventListener(getWidget(i).getElement(), "click", true, eventStack.get(i)); } if (!addEvent) eventStack.clear(); } void addIndicator() { HTML ind = new HTML(); //if (indicatorType == IndicatorType.slidetitles) // Utils.Eventing.addEventListener(ind.getElement(), "click", true, new IndicatorClickListener(getWidgetCount()+1)); add(ind); } void hide() { Utils.Widgets.removeCssClass(this, "showing"); } void show() { Utils.Widgets.addCssClass(this, "showing"); } void setActiveIndicator(int activeIndex) { configInficator(); Element eTemp = null; for (int i = 0; i < getWidgetCount(); i++) { eTemp = Element.as(getWidget(i).getElement()); if (eTemp == null) continue; eTemp.removeClassName("active"); eTemp.removeClassName("active-before"); eTemp.removeClassName("active-after"); if (indicatorType == IndicatorType.dot) eTemp.setInnerHTML(dotInactive); if (indicatorType == IndicatorType.square) eTemp.setInnerHTML(squareInactive); if (indicatorType == IndicatorType.numeric) eTemp.setInnerHTML((i + 1) + ""); if (indicatorType == IndicatorType.slidetitles && (i + 1) >= (activeIndex - 1) && (i + 1) <= (activeIndex + 1)) { eTemp.setInnerHTML(getSlide(i).getSlideTitle()); eTemp.getStyle().clearDisplay(); } else if (indicatorType == IndicatorType.slidetitles) { eTemp.getStyle().setDisplay(Display.NONE); } if (activeIndex == (i + 1)) { eTemp.addClassName("active"); if (indicatorType == IndicatorType.dot) eTemp.setInnerHTML(dotActive); if (indicatorType == IndicatorType.square) eTemp.setInnerHTML(squareActive); } else if ((i + 1) == (activeIndex - 1)) { if (indicatorType == IndicatorType.slidetitles) eTemp.addClassName("active-before"); } else if ((i + 1) == (activeIndex + 1)) { if (indicatorType == IndicatorType.slidetitles) eTemp.addClassName("active-after"); } } } } class IndicatorClickListener implements EventListener { private final int activeSlide; IndicatorClickListener(int activeSlide) { this.activeSlide = activeSlide; } @Override public void onBrowserEvent(Event event) { if (event.getTypeInt() == Event.ONCLICK) { if (activeSlide > getCurrentSlide()) { setCurrentSlide(getCurrentSlide() + 1); } else if (activeSlide < getCurrentSlide()) { setCurrentSlide(getCurrentSlide() - 1); } //event.preventDefault();//stopPropagation(); //Utils.Console("IndicatorClickListener: " + (activeSlide) + " - " + getCurrentSlide()); //setCurrentSlide(activeSlide); } } } }