| /* |
| * Copyright 2008 Google Inc. |
| * |
| * 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.google.gwt.user.client.ui; |
| |
| import com.google.gwt.aria.client.PressedValue; |
| import com.google.gwt.aria.client.Roles; |
| import com.google.gwt.dom.client.Document; |
| import com.google.gwt.dom.client.Element; |
| import com.google.gwt.dom.client.NativeEvent; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.safehtml.client.HasSafeHtml; |
| import com.google.gwt.safehtml.shared.SafeHtml; |
| import com.google.gwt.safehtml.shared.annotations.IsSafeHtml; |
| import com.google.gwt.user.client.DOM; |
| import com.google.gwt.user.client.Event; |
| |
| /** |
| * CustomButton is a base button class with built in support for a set number |
| * of button faces. |
| * |
| * Each face has its own style modifier. For example, the state for down and |
| * hovering is assigned the CSS modifier <i>down-hovering</i>. So, if the |
| * button's overall style name is <i>gwt-PushButton</i> then when showing the |
| * <code>down-hovering</code> face, the button's style is <i> |
| * gwt-PushButton-down-hovering</i>. The overall style name can be used to |
| * change the style of the button irrespective of the current face. |
| * |
| * <p> |
| * Each button face can be assigned is own image, text, or html contents. If no |
| * content is defined for a face, then the face will use the contents of another |
| * face. For example, if <code>down-hovering</code> does not have defined |
| * contents, it will use the contents defined by the <code>down</code> face. |
| * </p> |
| * |
| * <p> |
| * The supported faces are defined below: |
| * </p> |
| * <p> |
| * <table border="4"> |
| * <tr> |
| * |
| * <td><b>CSS style name</b></td> |
| * <td><b>Getter method</b></td> |
| * <td><b>description of face</b></td> |
| * <td><b>defaults to contents of face</b></td> |
| * </tr> |
| * |
| * <tr> |
| * <td>up</td> |
| * <td> {@link #getUpFace()}</td> |
| * <td>face shown when button is up</td> |
| * <td>none</td> |
| * </tr> |
| * |
| * <tr> |
| * <td>down</td> |
| * <td> {@link #getDownFace()}</td> |
| * <td>face shown when button is down</td> |
| * <td>up</td> |
| * </tr> |
| * |
| * <tr> |
| * <td>up-hovering</td> |
| * <td> {@link #getUpHoveringFace()}</td> |
| * <td>face shown when button is up and hovering</td> |
| * <td>up</td> |
| * </tr> |
| * |
| * <tr> |
| * <td>up-disabled</td> |
| * <td> {@link #getUpDisabledFace()}</td> |
| * <td>face shown when button is up and disabled</td> |
| * <td>up</td> |
| * </tr> |
| * |
| * <tr> |
| * <td>down-hovering</td> |
| * <td> {@link #getDownHoveringFace()}</td> |
| * <td>face shown when button is down and hovering</td> |
| * <td>down</td> |
| * </tr> |
| * |
| * <tr> |
| * <td>down-disabled</td> |
| * <td> {@link #getDownDisabledFace()}</td> |
| * <td>face shown when button is down and disabled</td> |
| * <td>down</td> |
| * </tr> |
| * </table> |
| * </p> |
| * |
| * <h3>Use in UiBinder Templates</h3> |
| * |
| * When working with CustomButton subclasses in |
| * {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates, you |
| * can set text and assign ImageResources for their various faces via |
| * child elements: |
| * <p> |
| * <dl> |
| * <dt><g:upFace> |
| * <dt><g:downFace> |
| * <dt><g:upHoveringFace> |
| * <dt><g:downHoveringFace> |
| * <dt><g:upDisabledFace> |
| * <dt><g:downDisabledFace> |
| * </dl> |
| * |
| * Each face element can take an optional <code>image</code> attribute |
| * and an html body. For example:<pre> |
| * <ui:image field='downButton'/> <!-- define an {@link com.google.gwt.resources.client.ImageResource ImageResource} --> |
| * |
| * <g:PushButton ui:field='pushButton' enabled='true'> |
| * <g:upFace> |
| * <b>click me</b> |
| * </gwt:upFace> |
| * <g:upHoveringFace> |
| * <b>Click ME!</b> |
| * </gwt:upHoveringFace> |
| * |
| * <g:downFace image='{downButton}'/> |
| * <g:downHoveringFace image='{downButton}'/> |
| * </g:PushButton> |
| * </pre> |
| */ |
| public abstract class CustomButton extends ButtonBase { |
| /** |
| * Represents a button's face. Each face is associated with its own style |
| * modifier and, optionally, its own contents html, text, or image. |
| */ |
| public abstract class Face implements HasHTML, HasSafeHtml { |
| private static final String STYLENAME_HTML_FACE = "html-face"; |
| private final Face delegateTo; |
| private Element face; |
| |
| /** |
| * Constructor for <code>Face</code>. Creates a new face that delegates to |
| * the supplied face. |
| * |
| * @param delegateTo default content provider |
| */ |
| private Face(Face delegateTo) { |
| this.delegateTo = delegateTo; |
| } |
| |
| /** |
| * Gets the face's contents as html. |
| * |
| * @return face's contents as html |
| * |
| */ |
| @Override |
| public String getHTML() { |
| return getFace().getInnerHTML(); |
| } |
| |
| /** |
| * Gets the face's contents as text. |
| * |
| * @return face's contents as text |
| * |
| */ |
| @Override |
| public String getText() { |
| return getFace().getInnerText(); |
| } |
| |
| /** |
| * Set the face's contents as html. |
| * |
| * @param html html to set as face's contents html |
| */ |
| @Override |
| public void setHTML(SafeHtml html) { |
| setHTML(html.asString()); |
| } |
| |
| /** |
| * Set the face's contents as html. |
| * |
| * @param html html to set as face's contents html |
| * |
| */ |
| @Override |
| public void setHTML(@IsSafeHtml String html) { |
| face = DOM.createDiv(); |
| UIObject.setStyleName(face, STYLENAME_HTML_FACE, true); |
| face.setInnerHTML(html); |
| updateButtonFace(); |
| } |
| |
| /** |
| * Set the face's contents as an image. |
| * |
| * @param image image to set as face contents |
| */ |
| public final void setImage(Image image) { |
| face = image.getElement(); |
| updateButtonFace(); |
| } |
| |
| /** |
| * Sets the face's contents as text. |
| * |
| * @param text text to set as face's contents |
| */ |
| @Override |
| public final void setText(String text) { |
| face = DOM.createDiv(); |
| UIObject.setStyleName(face, STYLENAME_HTML_FACE, true); |
| face.setInnerText(text); |
| updateButtonFace(); |
| } |
| |
| @Override |
| public final String toString() { |
| return this.getName(); |
| } |
| |
| /** |
| * Gets the ID associated with this face. This will be a bitwise and of all |
| * of the attributes that comprise this face. |
| */ |
| abstract int getFaceID(); |
| |
| /** |
| * Get the name of the face. This property is also used as a modifier on the |
| * <code>CustomButton</code> style. <p/> For instance, if the |
| * <code>CustomButton</code> style is "gwt-PushButton" and the face name is |
| * "up", then the CSS class name will be "gwt-PushButton-up". |
| * |
| * @return the face's name |
| */ |
| abstract String getName(); |
| |
| /** |
| * Gets the contents associated with this face. |
| */ |
| private Element getFace() { |
| if (face == null) { |
| if (delegateTo == null) { |
| // provide a default face as none was supplied. |
| face = DOM.createDiv(); |
| return face; |
| } else { |
| return delegateTo.getFace(); |
| } |
| } else { |
| return face; |
| } |
| } |
| |
| private void updateButtonFace() { |
| if (curFace != null && curFace.getFace() == this.getFace()) { |
| setCurrentFaceElement(face); |
| } |
| } |
| } |
| |
| private static final String STYLENAME_DEFAULT = "gwt-CustomButton"; |
| |
| /** |
| * Pressed Attribute bit. |
| */ |
| private static final int DOWN_ATTRIBUTE = 1; |
| |
| /** |
| * Hovering Attribute bit. |
| */ |
| private static final int HOVERING_ATTRIBUTE = 2; |
| |
| /** |
| * Disabled Attribute bit. |
| */ |
| private static final int DISABLED_ATTRIBUTE = 4; |
| |
| /** |
| * ID for up face. |
| */ |
| private static final int UP = 0; |
| |
| /** |
| * ID for down face. |
| */ |
| private static final int DOWN = DOWN_ATTRIBUTE; |
| |
| /** |
| * ID for upHovering face. |
| */ |
| private static final int UP_HOVERING = HOVERING_ATTRIBUTE; |
| |
| /** |
| * ID for downHovering face. |
| */ |
| private static final int DOWN_HOVERING = DOWN_ATTRIBUTE | HOVERING_ATTRIBUTE; |
| |
| /** |
| * ID for upDisabled face. |
| */ |
| private static final int UP_DISABLED = DISABLED_ATTRIBUTE; |
| |
| /** |
| * ID for downDisabled face. |
| */ |
| private static final int DOWN_DISABLED = DOWN | DISABLED_ATTRIBUTE; |
| |
| /** |
| * The button's current face element. |
| */ |
| private Element curFaceElement; |
| |
| /** |
| * The button's current face. |
| */ |
| private Face curFace; |
| |
| /** |
| * Face for up. |
| */ |
| private Face up; |
| |
| /** |
| * Face for down. |
| */ |
| private Face down; |
| |
| /** |
| * Face for downHover. |
| */ |
| private Face downHovering; |
| |
| /** |
| * Face for upHover. |
| */ |
| private Face upHovering; |
| |
| /** |
| * Face for upDisabled. |
| */ |
| private Face upDisabled; |
| |
| /** |
| * Face for downDisabled. |
| */ |
| private Face downDisabled; |
| |
| /** |
| * If <code>true</code>, this widget is capturing with the mouse held down. |
| */ |
| private boolean isCapturing; |
| |
| /** |
| * If <code>true</code>, this widget has focus with the space bar down. |
| */ |
| private boolean isFocusing; |
| |
| /** |
| * Used to decide whether to allow clicks to propagate up to the superclass |
| * or container elements. |
| */ |
| private boolean allowClick; |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upImage image for the default (up) face of the button |
| */ |
| public CustomButton(Image upImage) { |
| this(); |
| getUpFace().setImage(upImage); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upImage image for the default (up) face of the button |
| * @param handler the click handler |
| */ |
| public CustomButton(Image upImage, ClickHandler handler) { |
| this(upImage); |
| addClickHandler(handler); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upImage image for the default (up) face of the button |
| * @param listener the click listener |
| * @deprecated Use {@link #CustomButton(Image, ClickHandler)} instead |
| */ |
| @Deprecated |
| public CustomButton(Image upImage, ClickListener listener) { |
| this(upImage); |
| addClickListener(listener); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upImage image for the default (up) face of the button |
| * @param downImage image for the down face of the button |
| */ |
| public CustomButton(Image upImage, Image downImage) { |
| this(upImage); |
| getDownFace().setImage(downImage); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upImage image for the default (up) face of the button |
| * @param downImage image for the down face of the button |
| * @param handler clickListener |
| */ |
| public CustomButton(Image upImage, Image downImage, ClickHandler handler) { |
| this(upImage, handler); |
| getDownFace().setImage(downImage); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upImage image for the default (up) face of the button |
| * @param downImage image for the down face of the button |
| * @param listener clickListener |
| * @deprecated Use {@link #CustomButton(Image, Image, ClickHandler)} instead |
| */ |
| @Deprecated |
| public CustomButton(Image upImage, Image downImage, ClickListener listener) { |
| this(upImage, listener); |
| getDownFace().setImage(downImage); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upText the text for the default (up) face of the button |
| */ |
| public CustomButton(String upText) { |
| this(); |
| getUpFace().setText(upText); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upText the text for the default (up) face of the button |
| * @param handler the click handler |
| */ |
| public CustomButton(String upText, ClickHandler handler) { |
| this(upText); |
| addClickHandler(handler); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upText the text for the default (up) face of the button |
| * @param listener the click listener |
| * @deprecated Use {@link #CustomButton(String, ClickListener)} instead |
| */ |
| @Deprecated |
| public CustomButton(String upText, ClickListener listener) { |
| this(upText); |
| addClickListener(listener); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upText the text for the default (up) face of the button |
| * @param downText the text for the down face of the button |
| */ |
| public CustomButton(String upText, String downText) { |
| this(upText); |
| getDownFace().setText(downText); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upText the text for the default (up) face of the button |
| * @param downText the text for the down face of the button |
| * @param handler the click handler |
| */ |
| public CustomButton(String upText, String downText, ClickHandler handler) { |
| this(upText, downText); |
| addClickHandler(handler); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| * |
| * @param upText the text for the default (up) face of the button |
| * @param downText the text for the down face of the button |
| * @param listener the click listener |
| * @deprecated Use {@link #CustomButton(String, String, ClickHandler)} instead |
| */ |
| @Deprecated |
| public CustomButton(String upText, String downText, ClickListener listener) { |
| this(upText, downText); |
| addClickListener(listener); |
| } |
| |
| /** |
| * Constructor for <code>CustomButton</code>. |
| */ |
| protected CustomButton() { |
| // Use FocusPanel.impl rather than FocusWidget because only FocusPanel.impl |
| // works across browsers to create a focusable element. |
| super(FocusPanel.impl.createFocusable()); |
| sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS |
| | Event.KEYEVENTS); |
| setUpFace(createFace(null, "up", UP)); |
| setStyleName(STYLENAME_DEFAULT); |
| |
| // Add a11y role "button" |
| Roles.getButtonRole().set(getElement()); |
| } |
| |
| /** |
| * Gets the downDisabled face of the button. |
| * |
| * @return the downDisabled face |
| */ |
| public final Face getDownDisabledFace() { |
| if (downDisabled == null) { |
| setDownDisabledFace(createFace(getDownFace(), "down-disabled", |
| DOWN_DISABLED)); |
| } |
| return downDisabled; |
| } |
| |
| /** |
| * Gets the down face of the button. |
| * |
| * @return the down face |
| */ |
| public final Face getDownFace() { |
| if (down == null) { |
| setDownFace(createFace(getUpFace(), "down", DOWN)); |
| } |
| return down; |
| } |
| |
| /** |
| * Gets the downHovering face of the button. |
| * |
| * @return the downHovering face |
| */ |
| public final Face getDownHoveringFace() { |
| if (downHovering == null) { |
| setDownHoveringFace(createFace(getDownFace(), "down-hovering", |
| DOWN_HOVERING)); |
| } |
| return downHovering; |
| } |
| |
| /** |
| * Gets the current face's html. |
| * |
| * @return current face's html |
| */ |
| @Override |
| public String getHTML() { |
| return getCurrentFace().getHTML(); |
| } |
| |
| @Override |
| public int getTabIndex() { |
| return FocusPanel.impl.getTabIndex(getElement()); |
| } |
| |
| /** |
| * Gets the current face's text. |
| * |
| * @return current face's text |
| */ |
| @Override |
| public String getText() { |
| return getCurrentFace().getText(); |
| } |
| |
| /** |
| * Gets the upDisabled face of the button. |
| * |
| * @return the upDisabled face |
| */ |
| public final Face getUpDisabledFace() { |
| if (upDisabled == null) { |
| setUpDisabledFace(createFace(getUpFace(), "up-disabled", UP_DISABLED)); |
| } |
| return upDisabled; |
| } |
| |
| /** |
| * Gets the up face of the button. |
| * |
| * @return the up face |
| */ |
| public final Face getUpFace() { |
| return up; |
| } |
| |
| /** |
| * Gets the upHovering face of the button. |
| * |
| * @return the upHovering face |
| */ |
| public final Face getUpHoveringFace() { |
| if (upHovering == null) { |
| setUpHoveringFace(createFace(getUpFace(), "up-hovering", UP_HOVERING)); |
| } |
| return upHovering; |
| } |
| |
| @Override |
| public void onBrowserEvent(Event event) { |
| // Should not act on button if disabled. |
| if (isEnabled() == false) { |
| // This can happen when events are bubbled up from non-disabled children |
| return; |
| } |
| |
| int type = DOM.eventGetType(event); |
| switch (type) { |
| case Event.ONCLICK: |
| // If clicks are currently disallowed, keep it from bubbling or being |
| // passed to the superclass. |
| if (!allowClick) { |
| event.stopPropagation(); |
| return; |
| } |
| break; |
| case Event.ONMOUSEDOWN: |
| if (event.getButton() == Event.BUTTON_LEFT) { |
| setFocus(true); |
| onClickStart(); |
| DOM.setCapture(getElement()); |
| isCapturing = true; |
| // Prevent dragging (on some browsers); |
| event.preventDefault(); |
| } |
| break; |
| case Event.ONMOUSEUP: |
| if (isCapturing) { |
| isCapturing = false; |
| DOM.releaseCapture(getElement()); |
| if (isHovering() && event.getButton() == Event.BUTTON_LEFT) { |
| onClick(); |
| } |
| } |
| break; |
| case Event.ONMOUSEMOVE: |
| if (isCapturing) { |
| // Prevent dragging (on other browsers); |
| event.preventDefault(); |
| } |
| break; |
| case Event.ONMOUSEOUT: |
| Element to = DOM.eventGetToElement(event); |
| if (getElement().isOrHasChild(DOM.eventGetTarget(event)) |
| && (to == null || !getElement().isOrHasChild(to))) { |
| if (isCapturing) { |
| onClickCancel(); |
| } |
| setHovering(false); |
| } |
| break; |
| case Event.ONMOUSEOVER: |
| if (getElement().isOrHasChild(DOM.eventGetTarget(event))) { |
| setHovering(true); |
| if (isCapturing) { |
| onClickStart(); |
| } |
| } |
| break; |
| case Event.ONBLUR: |
| if (isFocusing) { |
| isFocusing = false; |
| onClickCancel(); |
| } |
| break; |
| case Event.ONLOSECAPTURE: |
| if (isCapturing) { |
| isCapturing = false; |
| onClickCancel(); |
| } |
| break; |
| } |
| |
| super.onBrowserEvent(event); |
| |
| // Synthesize clicks based on keyboard events AFTER the normal key handling. |
| if ((event.getTypeInt() & Event.KEYEVENTS) != 0) { |
| char keyCode = (char) event.getKeyCode(); |
| switch (type) { |
| case Event.ONKEYDOWN: |
| if (keyCode == ' ') { |
| isFocusing = true; |
| onClickStart(); |
| } |
| break; |
| case Event.ONKEYUP: |
| if (isFocusing && keyCode == ' ') { |
| isFocusing = false; |
| onClick(); |
| } |
| break; |
| case Event.ONKEYPRESS: |
| if (keyCode == '\n' || keyCode == '\r') { |
| onClickStart(); |
| onClick(); |
| } |
| break; |
| } |
| } |
| } |
| |
| @Override |
| public void setAccessKey(char key) { |
| FocusPanel.impl.setAccessKey(getElement(), key); |
| } |
| |
| /** |
| * Sets whether this button is enabled. |
| * |
| * @param enabled <code>true</code> to enable the button, <code>false</code> |
| * to disable it |
| */ |
| @Override |
| public final void setEnabled(boolean enabled) { |
| if (isEnabled() != enabled) { |
| toggleDisabled(); |
| super.setEnabled(enabled); |
| if (!enabled) { |
| cleanupCaptureState(); |
| Roles.getButtonRole().removeAriaPressedState(getElement()); |
| } else { |
| setAriaPressed(getCurrentFace()); |
| } |
| } |
| } |
| |
| @Override |
| public void setFocus(boolean focused) { |
| if (focused) { |
| FocusPanel.impl.focus(getElement()); |
| } else { |
| FocusPanel.impl.blur(getElement()); |
| } |
| } |
| |
| @Override |
| public void setHTML(SafeHtml html) { |
| setHTML(html.asString()); |
| } |
| |
| /** |
| * Sets the current face's html. |
| * |
| * @param html html to set |
| */ |
| @Override |
| public void setHTML(@IsSafeHtml String html) { |
| getCurrentFace().setHTML(html); |
| } |
| |
| @Override |
| public void setTabIndex(int index) { |
| FocusPanel.impl.setTabIndex(getElement(), index); |
| } |
| |
| /** |
| * Sets the current face's text. |
| * |
| * @param text text to set |
| */ |
| @Override |
| public void setText(String text) { |
| getCurrentFace().setText(text); |
| } |
| |
| /** |
| * Is this button down? |
| * |
| * @return <code>true</code> if the button is down |
| */ |
| protected boolean isDown() { |
| return (DOWN_ATTRIBUTE & getCurrentFace().getFaceID()) > 0; |
| } |
| |
| /** |
| * Overridden on attach to ensure that a button face has been chosen before |
| * the button is displayed. |
| */ |
| @Override |
| protected void onAttach() { |
| finishSetup(); |
| super.onAttach(); |
| } |
| |
| /** |
| * Called when the user finishes clicking on this button. The default behavior |
| * is to fire the click event to listeners. Subclasses that override |
| * {@link #onClickStart()} should override this method to restore the normal |
| * widget display. |
| */ |
| protected void onClick() { |
| // Allow the click we're about to synthesize to pass through to the |
| // superclass and containing elements. Element.dispatchEvent() is |
| // synchronous, so we simply set and clear the flag within this method. |
| allowClick = true; |
| |
| // Mouse coordinates are not always available (e.g., when the click is |
| // caused by a keyboard event). |
| NativeEvent evt = Document.get().createClickEvent(1, 0, 0, 0, 0, false, |
| false, false, false); |
| getElement().dispatchEvent(evt); |
| |
| allowClick = false; |
| } |
| |
| /** |
| * Called when the user aborts a click in progress; for example, by dragging |
| * the mouse outside of the button before releasing the mouse button. |
| * Subclasses that override {@link #onClickStart()} should override this |
| * method to restore the normal widget display. |
| */ |
| protected void onClickCancel() { |
| } |
| |
| /** |
| * Called when the user begins to click on this button. Subclasses may |
| * override this method to display the start of the click visually; such |
| * subclasses should also override {@link #onClick()} and |
| * {@link #onClickCancel()} to restore normal visual state. Each |
| * <code>onClickStart</code> will eventually be followed by either |
| * <code>onClick</code> or <code>onClickCancel</code>, depending on whether |
| * the click is completed. |
| */ |
| protected void onClickStart() { |
| } |
| |
| @Override |
| protected void onDetach() { |
| super.onDetach(); |
| cleanupCaptureState(); |
| setHovering(false); |
| } |
| |
| /** |
| * Sets whether this button is down. |
| * |
| * @param down <code>true</code> to press the button, <code>false</code> |
| * otherwise |
| */ |
| protected void setDown(boolean down) { |
| if (down != isDown()) { |
| toggleDown(); |
| } |
| } |
| |
| /** |
| * Common setup between constructors. |
| */ |
| void finishSetup() { |
| if (curFace == null) { |
| setCurrentFace(getUpFace()); |
| } |
| } |
| |
| void fireClickListeners(@SuppressWarnings("unused") Event nativeEvent) { |
| // TODO(ecc) Once event triggering is committed, should fire a native click event instead. |
| fireEvent(new ClickEvent() { |
| }); |
| } |
| |
| /** |
| * Gets the current face of the button. |
| * |
| * @return the current face |
| */ |
| |
| Face getCurrentFace() { |
| /* |
| * Implementation note: Package protected so we can use it when testing the |
| * button. |
| */ |
| finishSetup(); |
| return curFace; |
| } |
| |
| /** |
| * Is the mouse hovering over this button? |
| * |
| * @return <code>true</code> if the mouse is hovering |
| */ |
| final boolean isHovering() { |
| return (HOVERING_ATTRIBUTE & getCurrentFace().getFaceID()) > 0; |
| } |
| |
| void setCurrentFace(Face newFace) { |
| /* |
| * Implementation note: default access for testing. |
| */ |
| if (curFace != newFace) { |
| if (curFace != null) { |
| removeStyleDependentName(curFace.getName()); |
| } |
| curFace = newFace; |
| setCurrentFaceElement(newFace.getFace()); |
| addStyleDependentName(curFace.getName()); |
| |
| if (isEnabled()) { |
| setAriaPressed(newFace); |
| } |
| } |
| } |
| |
| /** |
| * Sets whether this button is hovering. |
| * |
| * @param hovering is this button hovering? |
| */ |
| final void setHovering(boolean hovering) { |
| if (hovering != isHovering()) { |
| toggleHover(); |
| } |
| } |
| |
| /** |
| * Toggle the up/down attribute. |
| */ |
| void toggleDown() { |
| int newFaceID = getCurrentFace().getFaceID() ^ DOWN_ATTRIBUTE; |
| setCurrentFace(newFaceID); |
| } |
| |
| /** |
| * Resets internal state if this button can no longer service events. This can |
| * occur when the widget becomes detached or disabled. |
| */ |
| private void cleanupCaptureState() { |
| if (isCapturing || isFocusing) { |
| DOM.releaseCapture(getElement()); |
| isCapturing = false; |
| isFocusing = false; |
| onClickCancel(); |
| } |
| } |
| |
| private Face createFace(Face delegateTo, final String name, final int faceID) { |
| return new Face(delegateTo) { |
| |
| @Override |
| public String getName() { |
| return name; |
| } |
| |
| @Override |
| int getFaceID() { |
| return faceID; |
| } |
| }; |
| } |
| |
| private Face getFaceFromID(int id) { |
| switch (id) { |
| case DOWN: |
| return getDownFace(); |
| case UP: |
| return getUpFace(); |
| case DOWN_HOVERING: |
| return getDownHoveringFace(); |
| case UP_HOVERING: |
| return getUpHoveringFace(); |
| case UP_DISABLED: |
| return getUpDisabledFace(); |
| case DOWN_DISABLED: |
| return getDownDisabledFace(); |
| default: |
| throw new IllegalStateException(id + " is not a known face id."); |
| } |
| } |
| |
| private void setAriaPressed(Face newFace) { |
| boolean pressed = (newFace.getFaceID() & DOWN_ATTRIBUTE) == 1; |
| Roles.getButtonRole().setAriaPressedState(getElement(), PressedValue.of(pressed)); |
| } |
| |
| /** |
| * Sets the current face based on the faceID. |
| * |
| * @param faceID sets the new face of the button |
| */ |
| private void setCurrentFace(int faceID) { |
| Face newFace = getFaceFromID(faceID); |
| setCurrentFace(newFace); |
| } |
| |
| private void setCurrentFaceElement(Element newFaceElement) { |
| if (curFaceElement != newFaceElement) { |
| if (curFaceElement != null) { |
| getElement().removeChild(curFaceElement); |
| } |
| curFaceElement = newFaceElement; |
| DOM.appendChild(getElement(), curFaceElement); |
| } |
| } |
| |
| /** |
| * Sets the downDisabled face of the button. |
| * |
| * @param downDisabled downDisabled face |
| */ |
| private void setDownDisabledFace(Face downDisabled) { |
| this.downDisabled = downDisabled; |
| } |
| |
| /** |
| * Sets the down face of the button. |
| * |
| * @param down the down face |
| */ |
| private void setDownFace(Face down) { |
| this.down = down; |
| } |
| |
| /** |
| * Sets the downHovering face of the button. |
| * |
| * @param downHovering hoverDown face |
| */ |
| private void setDownHoveringFace(Face downHovering) { |
| this.downHovering = downHovering; |
| } |
| |
| /** |
| * Sets the upDisabled face of the button. |
| * |
| * @param upDisabled upDisabled face |
| */ |
| private void setUpDisabledFace(Face upDisabled) { |
| this.upDisabled = upDisabled; |
| } |
| |
| /** |
| * Sets the up face of the button. |
| * |
| * @param up up face |
| */ |
| private void setUpFace(Face up) { |
| this.up = up; |
| } |
| |
| /** |
| * Sets the upHovering face of the button. |
| * |
| * @param upHovering upHovering face |
| */ |
| private void setUpHoveringFace(Face upHovering) { |
| this.upHovering = upHovering; |
| } |
| |
| /** |
| * Toggle the disabled attribute. |
| */ |
| private void toggleDisabled() { |
| // Toggle disabled. |
| int newFaceID = getCurrentFace().getFaceID() ^ DISABLED_ATTRIBUTE; |
| |
| // Remove hovering. |
| newFaceID &= ~HOVERING_ATTRIBUTE; |
| |
| // Sets the current face. |
| setCurrentFace(newFaceID); |
| } |
| |
| /** |
| * Toggle the hovering attribute. |
| */ |
| private void toggleHover() { |
| // Toggle hovering. |
| int newFaceID = getCurrentFace().getFaceID() ^ HOVERING_ATTRIBUTE; |
| |
| // Remove disabled. |
| newFaceID &= ~DISABLED_ATTRIBUTE; |
| setCurrentFace(newFaceID); |
| } |
| } |