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.dom.client.Document;
023import com.google.gwt.event.logical.shared.*;
024import com.google.gwt.event.shared.HandlerRegistration;
025import gwt.material.design.client.base.HasAxis;
026import gwt.material.design.client.base.HasType;
027import gwt.material.design.client.base.MaterialWidget;
028import gwt.material.design.client.base.mixin.CssNameMixin;
029import gwt.material.design.client.base.mixin.CssTypeMixin;
030import gwt.material.design.client.constants.Axis;
031import gwt.material.design.client.constants.CssName;
032import gwt.material.design.client.constants.FABType;
033
034import static gwt.material.design.client.js.JsMaterialElement.$;
035
036//@formatter:off
037
038/**
039 * Floating action buttons are used for a promoted action. They
040 * are distinguished by a circled icon floating above the UI and
041 * have motion behaviors that include morphing, launching, and a
042 * transferring anchor point.
043 * <p>
044 * <h3>UiBinder Usage:</h3>
045 * <pre>
046 * {@code
047 * <m:MaterialFAB>
048 *   <m:MaterialButton type="FLOATING" backgroundColor="BLUE" iconType="POLYMER" size="LARGE"/>
049 *   <m:MaterialFABList>
050 *     <m:MaterialButton type="FLOATING" backgroundColor="RED" iconType="POLYMER"/>
051 *     <m:MaterialButton type="FLOATING" backgroundColor="ORANGE" iconType="POLYMER"/>
052 *     <m:MaterialButton type="FLOATING" backgroundColor="WHITE" iconType="POLYMER" iconColor="BLACK"/>
053 *   </m:MaterialFABList>
054 * </m:MaterialFAB>}
055 * </pre>
056 * </p>
057 *
058 * @author kevzlou7979
059 * @see <a href="http://gwtmaterialdesign.github.io/gwt-material-demo/#buttons">Material FAB</a>
060 * @see <a href="https://material.io/guidelines/components/buttons-floating-action-button.html">Material Design Specification</a>
061 */
062//@formatter:on
063public class MaterialFAB extends MaterialWidget implements HasType<FABType>, HasAxis, HasCloseHandlers<MaterialFAB>,
064        HasOpenHandlers<MaterialFAB> {
065
066    private CssTypeMixin<FABType, MaterialFAB> typeMixin;
067    private CssNameMixin<MaterialFAB, Axis> axisMixin;
068
069    public MaterialFAB() {
070        super(Document.get().createDivElement(), CssName.FIXED_ACTION_BTN);
071    }
072
073    @Override
074    protected void onLoad() {
075        super.onLoad();
076
077        if (getType() == FABType.CLICK_ONLY) {
078            registerHandler(addClickHandler(clickEvent -> {
079                if (isEnabled()) {
080                    if (!isOpen()) {
081                        open();
082                    } else {
083                        close();
084                    }
085                }
086            }));
087        } else {
088            registerHandler(addMouseOverHandler(mouseOverEvent -> OpenEvent.fire(this, this)));
089            registerHandler(addMouseOutHandler(mouseOutEvent -> CloseEvent.fire(this, this)));
090        }
091    }
092
093    /**
094     * Open the FAB programmatically
095     */
096    public void open() {
097        open(true);
098    }
099
100    /**
101     * Open the FAB programmatically
102     *
103     * @param fireEvent flag whether this component fires Open Event
104     */
105    public void open(boolean fireEvent) {
106        if (fireEvent) {
107            OpenEvent.fire(this, this);
108        }
109        $(getElement()).openFAB();
110    }
111
112    /**
113     * Close the FAB programmatically
114     */
115    public void close() {
116        close(true);
117    }
118
119    /**
120     * Close the FAB programmatically
121     *
122     * @param fireEvent flag whether this component fires Close Event
123     */
124    public void close(boolean fireEvent) {
125        if (fireEvent) {
126            CloseEvent.fire(this, this);
127        }
128        $(getElement()).closeFAB();
129    }
130
131    @Override
132    public void setType(FABType type) {
133        getTypeMixin().setType(type);
134    }
135
136    @Override
137    public FABType getType() {
138        return getTypeMixin().getType();
139    }
140
141    @Override
142    public void setAxis(Axis axis) {
143        getAxisMixin().setCssName(axis);
144    }
145
146    @Override
147    public Axis getAxis() {
148        return getAxisMixin().getCssName();
149    }
150
151    public boolean isOpen() {
152        return getElement().hasClassName(CssName.ACTIVE);
153    }
154
155    @Override
156    public HandlerRegistration addCloseHandler(CloseHandler<MaterialFAB> handler) {
157        return addHandler(handler, CloseEvent.getType());
158    }
159
160    @Override
161    public HandlerRegistration addOpenHandler(OpenHandler handler) {
162        return addHandler(handler, OpenEvent.getType());
163    }
164
165    protected CssTypeMixin<FABType, MaterialFAB> getTypeMixin() {
166        if (typeMixin == null) {
167            typeMixin = new CssTypeMixin<>(this);
168        }
169        return typeMixin;
170    }
171
172    protected CssNameMixin<MaterialFAB, Axis> getAxisMixin() {
173        if (axisMixin == null) {
174            axisMixin = new CssNameMixin<>(this);
175        }
176        return axisMixin;
177    }
178}