package org.gwtoolbox.widget.client.button.version2;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FocusWidget;
import com.google.gwt.user.client.ui.Image;
import org.gwtoolbox.commons.ui.client.event.CompoundHandlerRegistration;
import org.gwtoolbox.widget.client.panel.LayoutUtils;
import org.gwtoolbox.widget.client.support.CssFloat;
/**
* A button component that triggers an action when a user clicks on it.
* <p/>
* <p></p>This button knows a number of faces for different situations. Each face is shown by switching between different
* CSS classes which are appended to the base CSS class "Button".
* <table>
* <tr><th>Face</th><th>Description</th><th>CSS class</th>
* <tr><td>"Up"</td><td>Shown when the user does not press or hover over the button (default face).</td><td>-</td></tr>
* <tr><td>"Down"</td><td>Shown when the user presses and holds the mouse down.</td><td>down</td></tr>
* <tr><td>"Disabled"</td><td>Shown when the button is disabled. See {@link #setEnabled(boolean)}.</td><td>disabled</td></tr>
* <tr><td>"Hover"</td><td>Shown when the user hovers over the button.</td><td>over</td></tr>
* </table>
* <p/>
* <p></p>The entire button is divided into three parts which each use their own CSS class: "left", "center" and "right".
*
* @author Tom van Zummeren
*/
public class Button extends FocusWidget {
private static final String BASE_CSS_CLASS = "Button";
private static final String LEFT_SIDE_CSS_CLASS = "Button-left";
private static final String CENTER_CSS_CLASS = "Button-center";
private static final String RIGHT_SIDE_CSS_CLASS = "Button-right";
private static final String FACE_HOVER_CSS_CLASS = "hover";
private static final String FACE_DOWN_CSS_CLASS = "down";
private static final String DISABLED_CSS_CLASS = "disabled";
private CompoundHandlerRegistration internalHandlerRegistration;
private Impl impl = GWT.create(Impl.class);
private Element center;
private Element currentImage;
private Element caption;
/**
* Constructs a new {@code Button} which only shows a text without an icon.
*
* @param captionText text to show on the button
*/
public Button(String captionText) {
this(captionText, (Image) null);
}
/**
* Constructs a new {@code Button} which only shows an icon.
*
* @param icon icon image to display left of the caption (may be {@code null})
*/
public Button(Image icon) {
this(null, icon);
}
/**
* Constructs a new {@code Button} which shows a text with an icon left of it.
*
* @param captionText text to show on the button
* @param icon icon image to display left of the caption (may be {@code null})
*/
public Button(String captionText, Image icon) {
this(captionText, icon, null);
}
/**
* Constructs a new {@code Button} with a click handler showing a text without an icon.
*
* @param captionText text to show on the button
* @param clickHandler the click clickHandler (may be {@code null})
*/
public Button(String captionText, ClickHandler clickHandler) {
this(captionText, null, clickHandler);
}
/**
* Constructs a new {@code Button} with a click handler showing a text without an icon.
*
* @param icon icon image to display left of the caption (may be {@code null})
* @param clickHandler the click clickHandler (may be {@code null})
*/
public Button(Image icon, ClickHandler clickHandler) {
this(null, icon, clickHandler);
}
/**
* Constructs a new {@code Button} with a text, an image and a click handler.
*
* @param captionText text to show on the button
* @param icon icon image to display left of the captionText (may be {@code null})
* @param clickHandler the click clickHandler (may be {@code null})
*/
public Button(String captionText, Image icon, ClickHandler clickHandler) {
super(DOM.createElement("div"));
Element container = getElement();
// TODO - Tom: Explain in a comment why it's needed to set the line-height when it's already defined in button.css
DOM.setStyleAttribute(container, "lineHeight", "23px");
LayoutUtils.setCssFloat(container, LocaleInfo.getCurrentLocale().isRTL() ? CssFloat.RIGHT : CssFloat.LEFT);
container.setClassName(BASE_CSS_CLASS);
Element leftSide = DOM.createElement("div");
container.appendChild(leftSide);
leftSide.setClassName(LEFT_SIDE_CSS_CLASS);
center = DOM.createElement("div");
container.appendChild(center);
center.setClassName(CENTER_CSS_CLASS);
caption = DOM.createElement("span");
center.appendChild(caption);
Element rightSide = DOM.createElement("div");
container.appendChild(rightSide);
rightSide.setClassName(RIGHT_SIDE_CSS_CLASS);
if (clickHandler != null) {
addClickHandler(clickHandler);
}
if (icon != null) {
setIcon(icon);
}
if (captionText != null) {
setCaption(captionText);
}
}
/**
* Changes the caption this button is showing.
*
* @param captionText new caption text to show
*/
public void setCaption(String captionText) {
caption.setInnerText(captionText);
if (currentImage != null) {
DOM.setStyleAttribute(caption, "marginLeft", "5px");
}
}
/**
* Sets the icon image to display to the left of the caption text.
*
* @param icon icon image to set ({@code null} to remove current icon)
*/
public void setIcon(Image icon) {
if (currentImage != null) {
center.removeChild(currentImage);
}
if (icon == null) {
return;
}
int iconHeight = icon.getHeight();
int margin = (23 - iconHeight) / 2;
currentImage = icon.getElement();
DOM.setStyleAttribute(currentImage, "marginTop", margin + "px");
center.insertFirst(currentImage);
}
/**
* {@inheritDoc}
*/
@Override
protected void onLoad() {
internalHandlerRegistration = new CompoundHandlerRegistration();
// Change to the "hover" face when mouse hovers over the button
internalHandlerRegistration.addRegistration(addMouseOverHandler(new MouseOverHandler() {
public void onMouseOver(MouseOverEvent event) {
Button.this.addStyleDependentName(FACE_HOVER_CSS_CLASS);
}
}));
// Remove the "hover" face when mouse hovers out of the button
internalHandlerRegistration.addRegistration(addMouseOutHandler(new MouseOutHandler() {
public void onMouseOut(MouseOutEvent event) {
Button.this.removeStyleDependentName(FACE_HOVER_CSS_CLASS);
Button.this.removeStyleDependentName(FACE_DOWN_CSS_CLASS);
}
}));
// Change to the "down" face when the button is pressed
internalHandlerRegistration.addRegistration(addMouseDownHandler(new MouseDownHandler() {
public void onMouseDown(MouseDownEvent event) {
Button.this.addStyleDependentName(FACE_DOWN_CSS_CLASS);
}
}));
// Remove the "down" face when the button is released
internalHandlerRegistration.addRegistration(addMouseUpHandler(new MouseUpHandler() {
public void onMouseUp(MouseUpEvent event) {
Button.this.removeStyleDependentName(FACE_DOWN_CSS_CLASS);
}
}));
impl.disableTextSelection(getElement());
}
/**
* {@inheritDoc}
*/
@Override
protected void onUnload() {
super.onUnload();
if (internalHandlerRegistration != null) {
internalHandlerRegistration.removeHandler();
internalHandlerRegistration = null;
}
}
/**
* {@inheritDoc}
*/
@Override
public void onBrowserEvent(Event event) {
// Events should only be handled when the button is enabled.
if (isEnabled()) {
super.onBrowserEvent(event);
}
}
/**
* Sets the width of this button as a string. This is the same string you would set on a regular HTML element.
* <p></p>Examples: "100px", "50em", "75pt"
*/
@Override
public void setWidth(String width) {
// Sets the width on the style property of the element, instead of the width attribute like the super does.
getElement().getStyle().setProperty("width", width);
}
/**
* @see Style#setWidth(double, com.google.gwt.dom.client.Style.Unit)
*/
public void setWidth(double value, Style.Unit unit) {
getElement().getStyle().setWidth(value, unit);
}
/**
* Sets the width of this button in pixels.
*
* @param pixels amount of pixels to set the width on
* @see #setWidth(double, com.google.gwt.dom.client.Style.Unit)
*/
public void setWidthInPixels(double pixels) {
setWidth(pixels, Style.Unit.PX);
}
/**
* {@inheritDoc}
*/
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (enabled) {
// Remove the disabled face's CSS class
removeStyleDependentName(DISABLED_CSS_CLASS);
} else {
// Remove any existing faces and add the disabled face's CSS class
setStyleName(BASE_CSS_CLASS);
addStyleDependentName(DISABLED_CSS_CLASS);
}
}
//================================================= Inner Classes ==================================================
private static class Impl {
public void disableTextSelection(Element element) {
}
}
private static class ImplIE extends Impl {
/**
* Disables selecting text on this button when using Internet Explorer.
*
* @param element the element to perform the 'IE fix' on
*/
@Override
public native void disableTextSelection(Element element) /*-{
element.onselectstart = function() { return false; };
}-*/;
}
}