/* * Copyright 2014 cruxframework.org. * * 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 org.cruxframework.crux.smartfaces.client.swappanel; import org.cruxframework.crux.core.client.event.swap.HasSwapHandlers; import org.cruxframework.crux.core.client.event.swap.SwapEvent; import org.cruxframework.crux.core.client.event.swap.SwapHandler; import org.cruxframework.crux.smartfaces.client.backbone.common.FacesBackboneResourcesCommon; import org.cruxframework.crux.smartfaces.client.swappanel.SwapAnimation.SwapAnimationCallback; import org.cruxframework.crux.smartfaces.client.swappanel.SwapAnimation.SwapAnimationHandler; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.logical.shared.AttachEvent; import com.google.gwt.event.logical.shared.AttachEvent.Handler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HasAnimation; import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.Widget; /** * A panel that allows animated swap between widgets. * * @author bruno.rafael * */ public class SwapPanel extends Composite implements HasSwapHandlers, HasAnimation { /** * Default css style of the current panel. */ public static final String CURRENT_STYLE_NAME = "faces-SwapPanel-currentPanel"; /** * Default css style of the component. */ public static final String DEFAULT_STYLE_NAME = "faces-SwapPanel"; /** * Default css style of the next panel. */ public static final String NEXT_STYLE_NAME = "faces-SwapPanel-nextPanel"; private boolean animating = false; private SwapAnimation animation; private double animationDuration = -1; private boolean animationEnabled = true; private FlowPanel contentPanel; private SimplePanel currentPanel = new SimplePanel(); private boolean fitToChildrenHeight = true; private String height = "auto"; private SimplePanel nextPanel = new SimplePanel(); /** * The default constructor. */ public SwapPanel() { FacesBackboneResourcesCommon.INSTANCE.css().ensureInjected(); contentPanel = new FlowPanel(); initWidget(contentPanel); setStyleName(DEFAULT_STYLE_NAME); currentPanel.setStyleName(CURRENT_STYLE_NAME); nextPanel.setStyleName(NEXT_STYLE_NAME); contentPanel.add(currentPanel); contentPanel.add(nextPanel); } /** * @param animation Type of animation */ public SwapPanel(SwapAnimation animation) { this(); this.animation = animation; } /** * @param animation type of animation * @param enabled If the animation is enabled */ public SwapPanel(SwapAnimation animation, boolean enabled) { this(); this.animation = animation; this.animationEnabled = enabled; } @Override public HandlerRegistration addSwapHandler(SwapHandler handler) { return addHandler(handler, SwapEvent.getType()); } /** * Clear the Panel. */ public void clear() { currentPanel.clear(); nextPanel.clear(); } /** * @return Animation */ public SwapAnimation getAnimation() { return animation; } /** Return the current widget in the panel. * * @return Widget the current widget */ public Widget getCurrentWidget() { return this.currentPanel.getWidget(); } public boolean isAnimating() { return animating; } @Override public boolean isAnimationEnabled() { return animationEnabled; } public boolean isFitToChildrenHeight() { return fitToChildrenHeight; } /** * @param animation type Animation type */ public void setAnimation(SwapAnimation animation) { this.animation = animation; } /** * Set the duration for the animations * @param duration animations duration in seconds */ public void setAnimationDuration(double duration) { this.animationDuration = duration; } @Override public void setAnimationEnabled(boolean enable) { this.animationEnabled = enable; } /** * Sets the widget that will be initially visible on this panel. * @param widget widget that will be initially */ public void setCurrentWidget(final Widget widget) { if (widget != null) { if (isAnimating()) { completedAnimation(null); } setPanelHeightOnWidgetAttached(widget); this.currentPanel.clear(); this.currentPanel.add(widget); } } public void setFitToChildrenHeight(boolean fitToChildrenHeight) { if (!this.fitToChildrenHeight && fitToChildrenHeight) { currentPanel.setHeight("auto"); nextPanel.setHeight("auto"); } else if (!fitToChildrenHeight) { setHeight(height); } this.fitToChildrenHeight = fitToChildrenHeight; } @Override public void setHeight(String height) { this.height = height; super.setHeight(height); if (!fitToChildrenHeight) { currentPanel.setHeight(height); nextPanel.setHeight(height); } } @Override public void setStyleName(String style) { super.setStyleName(style); addStyleName(FacesBackboneResourcesCommon.INSTANCE.css().facesBackboneSwapPanel()); } @Override public void setStyleName(String style, boolean add) { super.setStyleName(style, add); if (!add) { addStyleName(FacesBackboneResourcesCommon.INSTANCE.css().facesBackboneSwapPanel()); } } /** * Changes the widget being shown on this widget. * @param widget - the widget will be insert in the swapPanel */ public void transitTo(final Widget widget) { transitTo(widget, animation, this.animationEnabled, null); } /** * Changes the widget being shown on this widget. * @param widget - the widget will be insert in the swapPanel * @param animation - type of animation */ public void transitTo(final Widget widget, SwapAnimation animation) { transitTo(widget, animation, this.animationEnabled, null); } /** * Changes the widget being shown on this widget. * @param widget - the widget will be insert in the swapPanel * @param animation - type of animation * @param animationEnabled - type of animation */ public void transitTo(final Widget widget, SwapAnimation animation, boolean animationEnabled, final SwapAnimationCallback callback) { if (!animating) { setPanelHeightOnWidgetAttached(widget); animating = true; nextPanel.clear(); nextPanel.add(widget); if (animationEnabled && animation != null) { animation.animate(nextPanel, currentPanel, new SwapAnimationHandler() { @Override public void setInElementFinalState(Widget in) { Style style = in.getElement().getStyle(); style.setDisplay(Display.NONE); } @Override public void setInElementInitialState(Widget in) { Style style = in.getElement().getStyle(); style.setDisplay(Display.BLOCK); style.setTop(0, Unit.PX); } @Override public void setOutElementFinalState(Widget out) { Style style = out.getElement().getStyle(); style.setDisplay(Display.BLOCK); } @Override public void setOutElementInitialState(Widget out) { Style style = out.getElement().getStyle(); style.setDisplay(Display.NONE); style.setTop(0, Unit.PX); } }, new SwapAnimationCallback() { @Override public void onAnimationCompleted() { completedAnimation(callback); } }, animationDuration); } else { completedAnimation(callback); } } } private void completedAnimation(final SwapAnimationCallback callback) { if (animating) { currentPanel.clear(); currentPanel.add(nextPanel.getWidget()); nextPanel.clear(); animating = false; SwapEvent.fire(SwapPanel.this); if (callback != null) { callback.onAnimationCompleted(); } } } private void setPanelHeightOnWidgetAttached(final Widget widget) { if (fitToChildrenHeight) { widget.addAttachHandler(new Handler() { @Override public void onAttachOrDetach(AttachEvent event) { if (event.isAttached()) { SwapPanel.this.setHeight(widget.getOffsetHeight() + "px"); } } }); } } }