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.client.ui;
021
022import com.google.gwt.core.client.GWT;
023import com.google.gwt.core.client.Scheduler;
024import com.google.gwt.user.client.ui.Widget;
025import gwt.material.design.client.js.JsPushpinOptions;
026
027import static gwt.material.design.client.js.JsMaterialElement.$;
028//@formatter:off
029
030/**
031 * Pushpin is our fixed positioning plugin. You can check out our live examples: the fixed Table of Contents on the right.
032 * <h3>UiBinder Usage:</h3>
033 * <p>
034 * <pre>
035 * {@code
036 * // CAN BE CALLED AS A HELPER STATIC CONTEXT
037 * MaterialPushpin.apply(target, source.getOffsetHeight() + 600);
038 *
039 * // INSTANTIATE THE PUSHPIN COMPONENT
040 * MaterialPushpin pushpin = new MaterialPushpin();
041 * pushpin.setWidget(source);
042 * pushpin.setTop(300.0);
043 * pushpin.setOffset(64.0);
044 * pushpin.setBottom(500.0);
045 * pushpin.apply();
046 * }
047 * </pre>
048 *
049 * @author kevzlou7979
050 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#pushpin">Material PushPin</a>
051 */
052public class MaterialPushpin {
053
054    private Widget widget;
055    private JsPushpinOptions options = new JsPushpinOptions();
056
057    public MaterialPushpin() {}
058
059    /**
060     * Apply the pushpin feature into the target widget
061     */
062    public void apply() {
063        Scheduler.get().scheduleDeferred(() -> {
064            if (widget != null) {
065                $(widget.getElement()).pushpin(options);
066            } else {
067                GWT.log("Please set your widget before applying the pushpin", new IllegalStateException());
068            }
069        });
070    }
071
072    /**
073     * A pushpinned element has 3 states. One above and below the scrolling threshold,
074     * and the pinned state where the element becomes fixed.
075     *
076     * @param widget - Target widget to apply the pushpin feature
077     * @param offset - The offset from the top the element will be fixed at. (Default: 0)
078     */
079    public static void apply(Widget widget, Double offset) {
080        apply(widget, null, null, offset);
081    }
082
083    /**
084     * A pushpinned element has 3 states. One above and below the scrolling threshold,
085     * and the pinned state where the element becomes fixed.
086     *
087     * @param widget - Target widget to apply the pushpin feature
088     * @param top    - The distance in pixels from the top of the page where the element becomes fixed. (Default: 0)
089    * @param offset - The offset from the top the element will be fixed at. (Default: 0)
090     */
091    public static void apply(Widget widget, Double top, Double offset) {
092        apply(widget, top, null, offset);
093    }
094
095    /**
096     * A pushpinned element has 3 states. One above and below the scrolling threshold,
097     * and the pinned state where the element becomes fixed.
098     *
099     * @param widget - Target widget to apply the pushpin feature
100     * @param top    - The distance in pixels from the top of the page where the element becomes fixed. (Default: 0)
101     * @param bottom - The distance in pixels from the top of the page where the elements stops being fixed. (Default: Infinity)
102     * @param offset - The offset from the top the element will be fixed at. (Default: 0)
103     */
104    public static void apply(Widget widget, Double top, Double bottom, Double offset) {
105        MaterialPushpin pushpin = new MaterialPushpin();
106        pushpin.setWidget(widget);
107        pushpin.setTop(top);
108        pushpin.setBottom(bottom);
109        pushpin.setOffset(offset);
110        pushpin.apply();
111    }
112
113    /**
114     * Get the target widget which the pushpin was applied
115     */
116    public Widget getWidget() {
117        return widget;
118    }
119
120    /**
121     * Set the target widget to apply the pushpin feature
122     */
123    public void setWidget(Widget widget) {
124        this.widget = widget;
125    }
126
127    /**
128     * Get the offset from the top the element will be fixd at.
129     */
130    public Double getOffset() {
131        return options.offset;
132    }
133
134    /**
135     * Set the offset from the top the element will be fixed at. (Default: 0)
136     */
137    public void setOffset(Double offset) {
138        options.offset = (offset != null) ? offset : 0;
139    }
140
141    /**
142     * Get the distance in pixels from the top of the page where the element becomes fixed. (Default: 0)
143     */
144    public Double getTop() {
145        return options.top;
146    }
147
148    /**
149     * Set the distance in pixels from the top of the page where the element becomes fixed. (Default: 0)
150     */
151    public void setTop(Double top) {
152        options.top = (top != null) ? top : 0;
153    }
154
155    /**
156     * Get the distance in pixels from the top of the page where the elements stops being fixed. (Default: Infinity)
157     */
158    public Double getBottom() {
159        return options.bottom;
160    }
161
162    /**
163     * Set the distance in pixels from the top of the page where the elements stops being fixed. (Default: Infinity)
164     */
165    public void setBottom(Double bottom) {
166        // Avoid overriding the bottom property if it's null,
167        // as it takes "Infinity" as the default value
168        if (bottom != null) {
169            options.bottom = bottom;
170        }
171    }
172}