001/*
002 * #%L
003 * GwtMaterial
004 * %%
005 * Copyright (C) 2015 - 2017 GwtMaterialDesign
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 * 
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 * 
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package gwt.material.design.addins.client.overlay;
021
022import com.google.gwt.dom.client.Document;
023import com.google.gwt.dom.client.Element;
024import com.google.gwt.dom.client.Style;
025import com.google.gwt.event.logical.shared.*;
026import com.google.gwt.event.shared.HandlerRegistration;
027import gwt.material.design.addins.client.MaterialAddins;
028import gwt.material.design.addins.client.base.constants.AddinsCssName;
029import gwt.material.design.addins.client.pathanimator.MaterialPathAnimator;
030import gwt.material.design.client.MaterialDesignBase;
031import gwt.material.design.client.base.HasDurationTransition;
032import gwt.material.design.client.base.MaterialWidget;
033import gwt.material.design.client.constants.Color;
034
035import static gwt.material.design.jquery.client.api.JQuery.$;
036
037//@formatter:off
038
039/**
040 * It's an overlay panel layout wherein you can put as many widgets as you want and design it.
041 * You can do advance stuff by implementing Path Animator into the overlay panel container.
042 * <p>
043 * <h3>XML Namespace Declaration</h3>
044 * <pre>
045 * {@code
046 * xmlns:ma='urn:import:gwt.material.design.addins.client'
047 * }
048 * </pre>
049 * <p>
050 * <h3>UiBinder Usage:</h3>
051 * <pre>
052 * {@code
053 * <ma:overlay.MaterialOverlay background="blue">
054 *      &lt;-- Some content here -->
055 * </ma:overlay.MaterialOverlay>
056 * }
057 * </pre>
058 *
059 * @author kevzlou7979
060 */
061//@formatter:on
062public class MaterialOverlay extends MaterialWidget implements HasOpenHandlers<MaterialOverlay>,
063        HasCloseHandlers<MaterialOverlay>, HasDurationTransition {
064
065    static {
066        if (MaterialAddins.isDebug()) {
067            MaterialDesignBase.injectCss(MaterialOverlayDebugClientBundle.INSTANCE.overlayCssDebug());
068        } else {
069            MaterialDesignBase.injectCss(MaterialOverlayClientBundle.INSTANCE.overlayCss());
070        }
071    }
072
073    private Element sourceElement;
074    private MaterialPathAnimator animator = new MaterialPathAnimator();
075
076    public MaterialOverlay() {
077        super(Document.get().createDivElement(), AddinsCssName.OVERLAY_PANEL);
078    }
079
080    public MaterialOverlay(Color backgroundColor) {
081        this();
082        setBackgroundColor(backgroundColor);
083    }
084
085    public MaterialOverlay(Color backgroundColor, Style.Visibility visibility, Double opacity) {
086        this(backgroundColor);
087        setVisibility(visibility);
088        setOpacity(opacity);
089    }
090
091    public void open(MaterialWidget source) {
092        open(source.getElement());
093    }
094
095    /**
096     * Open the Overlay Panel with Path Animator applied
097     */
098    public void open(Element sourceElement) {
099        this.sourceElement = sourceElement;
100        $("body").attr("style", "overflow: hidden !important");
101        animator.setSourceElement(sourceElement);
102        animator.setTargetElement(getElement());
103        animator.animate();
104        OpenEvent.fire(this, this);
105    }
106
107    /**
108     * Open the Overlay Panel without Path Animator
109     */
110    public void open() {
111        setVisibility(Style.Visibility.VISIBLE);
112        setOpacity(1);
113        OpenEvent.fire(this, this);
114    }
115
116    /**
117     * Close the Overlay Panel with Path Animator applied
118     */
119    public void close() {
120        if ($(getElement()).parents(AddinsCssName.OVERLAY_PANEL).length() == 1) {
121            body().attr("style", "overflow: hidden !important");
122        } else {
123            body().attr("style", "overflow: auto !important");
124        }
125        if (sourceElement != null) {
126            animator.reverseAnimate();
127        }
128        CloseEvent.fire(this, this);
129    }
130
131    /**
132     * Get source element for path animator
133     */
134    public Element getSourceElement() {
135        return sourceElement;
136    }
137
138    /**
139     * Set source element for path animator
140     */
141    public void setSourceElement(Element sourceElement) {
142        this.sourceElement = sourceElement;
143    }
144
145    @Override
146    public int getDuration() {
147        return animator.getDuration();
148    }
149
150    @Override
151    public void setDuration(int duration) {
152        animator.setDuration(duration);
153    }
154
155    public int getTargetShowDuration() {
156        return animator.getTargetShowDuration();
157    }
158
159    /**
160     * Duration (in milliseconds) of targetElement to become visible, if hidden initially. The library will automatically try to figure this out from the element's computed styles. Default is 0 seconds.
161     */
162    public void setTargetShowDuration(int targetShowDuration) {
163        animator.setTargetShowDuration(targetShowDuration);
164    }
165
166    public int getExtraTransitionDuration() {
167        return animator.getExtraTransitionDuration();
168    }
169
170    /**
171     * Extra duration (in milliseconds) of targetElement to provide visual continuity between the animation and the rendering of the targetElement. Default is 1 second
172     */
173    public void setExtraTransitionDuration(int extraTransitionDuration) {
174        animator.setExtraTransitionDuration(extraTransitionDuration);
175    }
176
177    public void setRelativeToWindow(boolean relativeToWindow) {
178        animator.setRelativeToWindow(relativeToWindow);
179    }
180
181    public boolean isRelativeToWindow() {
182        return animator.isRelativeToWindow();
183    }
184
185    @Override
186    public HandlerRegistration addCloseHandler(CloseHandler<MaterialOverlay> closeHandler) {
187        return addHandler(new CloseHandler<MaterialOverlay>() {
188            @Override
189            public void onClose(CloseEvent<MaterialOverlay> closeEvent) {
190                if (isEnabled()) {
191                    closeHandler.onClose(closeEvent);
192                }
193            }
194        }, CloseEvent.getType());
195    }
196
197    @Override
198    public HandlerRegistration addOpenHandler(OpenHandler<MaterialOverlay> openHandler) {
199        return addHandler(new OpenHandler<MaterialOverlay>() {
200            @Override
201            public void onOpen(OpenEvent<MaterialOverlay> openEvent) {
202                if (isEnabled()) {
203                    openHandler.onOpen(openEvent);
204                }
205            }
206        }, OpenEvent.getType());
207    }
208}