package org.gwtoolbox.widget.client.button;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.event.shared.HandlerRegistration;
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.Composite;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.SimplePanel;
import org.gwtoolbox.widget.client.event.custom.HasToggleHandlers;
import org.gwtoolbox.widget.client.event.custom.ToggleEvent;
import org.gwtoolbox.widget.client.event.custom.ToggleHandler;
import java.util.HashMap;
import java.util.Map;
/**
* @author Uri Boness
*/
public class ImageToggleButton extends Composite implements HasToggleHandlers {
private final static int UP = 1;
private final static int DOWN = 2;
private final static int HOVERING = 4;
private final static int DISABLED = 8;
private Map<Integer, Face> faces = new HashMap<Integer, Face>();
private boolean enabled = true;
private boolean hovering;
private boolean down;
private boolean isCapturing;
private String group;
private final static Map<String, Group> groupByName = new HashMap<String, Group>();
private Face currentFace;
private SimplePanel imagePane;
private HandlerRegistration[] internalHandlerRegistrations;
public ImageToggleButton(Image image) {
initFaces(image);
imagePane = new SimplePanel();
DOM.setStyleAttribute(imagePane.getElement(), "position", "relative");
initWidget(imagePane);
imagePane.setStylePrimaryName("ImageToggleButton");
setCurrentFace(UP);
}
@Override
public void setSize(String width, String height) {
throw new UnsupportedOperationException("A ToolButton as a fixed size of 25 x 25 pixels");
}
public HandlerRegistration addToggleHandler(ToggleHandler handler) {
return addHandler(handler, ToggleEvent.getType());
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
updateFace();
}
public void toggle() {
toggle(true);
}
public void setDown(boolean down) {
setState(down, false);
}
public boolean isDown() {
return down;
}
public void setGroup(String group) {
this.group = group;
if (!groupByName.containsKey(group)) {
groupByName.put(group, new Group());
}
}
public Face getUpFace() {
return faces.get(UP);
}
public Face getUpHoverFace() {
return faces.get(UP | HOVERING);
}
public Face getUpDisabledFace() {
return faces.get(UP | DISABLED);
}
public Face getUpDisabledHoverFace() {
return faces.get(UP | HOVERING | DISABLED);
}
public Face getDownFace() {
return faces.get(DOWN);
}
public Face getDownHoverFace() {
return faces.get(DOWN | HOVERING);
}
public Face getDownDisabledFace() {
return faces.get(DOWN | DISABLED);
}
public Face getDownDisabledHoverFace() {
return faces.get(DOWN | DISABLED | HOVERING);
}
//================================================ Helper Methods ==================================================
@Override
protected void onLoad() {
super.onLoad();
internalHandlerRegistrations = new HandlerRegistration[6];
internalHandlerRegistrations[0] = addDomHandler(new MouseDownHandler() {
public void onMouseDown(MouseDownEvent event) {
if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
DOM.setCapture(getElement());
isCapturing = true;
// Prevent dragging (on some browsers);
event.preventDefault();
setCurrentFace(DOWN);
}
}
}, MouseDownEvent.getType());
internalHandlerRegistrations[1] = addDomHandler(new MouseUpHandler() {
public void onMouseUp(MouseUpEvent event) {
if (isCapturing) {
isCapturing = false;
DOM.releaseCapture(getElement());
if (hovering && event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
toggle();
}
}
}
}, MouseUpEvent.getType());
internalHandlerRegistrations[2] = addDomHandler(new MouseMoveHandler() {
public void onMouseMove(MouseMoveEvent event) {
if (isCapturing) {
event.preventDefault();
}
}
}, MouseMoveEvent.getType());
internalHandlerRegistrations[3] = addDomHandler(new MouseOutHandler() {
public void onMouseOut(MouseOutEvent event) {
Element from = event.getNativeEvent().getEventTarget().cast();
Element to = event.getRelatedTarget().cast();
if (DOM.isOrHasChild(getElement(), from) && (to == null || !DOM.isOrHasChild(getElement(), to))) {
setHovering(false);
}
}
}, MouseOutEvent.getType());
internalHandlerRegistrations[4] = addDomHandler(new MouseOverHandler() {
public void onMouseOver(MouseOverEvent event) {
Element element = event.getNativeEvent().getEventTarget().cast();
if (DOM.isOrHasChild(getElement(), element)) {
setHovering(true);
}
}
}, MouseOverEvent.getType());
internalHandlerRegistrations[5] = addDomHandler(new LoseCaptureHandler() {
public void onLoseCapture(LoseCaptureEvent event) {
cleanupCaptureState();
}
}, LoseCaptureEvent.getType());
}
@Override
protected void onUnload() {
super.onUnload();
for (HandlerRegistration registration : internalHandlerRegistrations) {
registration.removeHandler();
}
internalHandlerRegistrations = null;
}
@Override
public void onBrowserEvent(Event event) {
if (isEnabled()) {
super.onBrowserEvent(event);
}
}
private void cleanupCaptureState() {
if (isCapturing) {
DOM.releaseCapture(getElement());
isCapturing = false;
}
}
private void toggle(boolean fireEvent) {
setState(!isDown(), fireEvent);
}
private void setState(boolean down, boolean fireEvent) {
this.down = down;
updateFace();
if (down && group != null) {
groupByName.get(group).handleClicked(this);
}
if (fireEvent) {
ToggleEvent.fire(this, down);
}
}
private void initFaces(Image up) {
Face upFace = new Face("", up);
faces.put(UP, upFace);
faces.put(UP | HOVERING, new Face("hover", upFace));
faces.put(UP | DISABLED, new Face("disabled", upFace));
faces.put(UP | DISABLED | HOVERING, new Face("disabled-hover", upFace));
Face downFace = new Face("down", upFace);
faces.put(DOWN, downFace);
faces.put(DOWN | HOVERING, new Face("down-hover", downFace));
faces.put(DOWN | DISABLED, new Face("down-disabled", downFace));
faces.put(DOWN | DISABLED | HOVERING, new Face("down-disabled-hover", downFace));
}
private void updateFace() {
if (!down && !hovering && enabled) { // up
setCurrentFace(UP);
return;
}
if (!down && hovering && enabled) { // up hovering
setCurrentFace(UP | HOVERING);
return;
}
if (!down && !hovering && !enabled) { // up disabled
setCurrentFace(UP | DISABLED);
return;
}
if (!down && hovering && !enabled) { // up disabled hovering
setCurrentFace(UP | DISABLED | HOVERING);
return;
}
if (down && !hovering && enabled) { // down
setCurrentFace(DOWN);
return;
}
if (down && hovering && enabled) { // down hovering
setCurrentFace(DOWN | HOVERING);
}
if (down && !hovering && !enabled) { // down diabled
setCurrentFace(DOWN | DISABLED);
return;
}
if (down && hovering && !enabled) { // down diabled hovering
setCurrentFace(DOWN | DISABLED);
return;
}
}
private void setCurrentFace(int faceType) {
Face face = faces.get(faceType);
setCurrentFace(face);
}
private void setCurrentFace(Face face) {
if (currentFace != null) {
imagePane.removeStyleDependentName(currentFace.getKey());
}
currentFace = face;
Image image = face.getImage();
setWidth((image.getWidth() + 4) + "px");
setHeight((image.getHeight() + 4) + "px");
int left = 2;
int top = 2;
imagePane.setWidget(face.getImage());
DOM.setStyleAttribute(image.getElement(), "position", "relative");
DOM.setStyleAttribute(image.getElement(), "left", left + "px");
DOM.setStyleAttribute(image.getElement(), "top", top + "px");
String key = currentFace.getKey();
if (key.length() != 0) {
imagePane.addStyleDependentName(key);
}
}
private void setHovering(boolean hovering) {
this.hovering = hovering;
updateFace();
}
//================================================= Inner Classes ==================================================
public class Face {
private String key;
private Image image;
private Face fallback;
private Face(String key, Face fallback) {
this(key, null, fallback);
}
private Face(String key, Image image) {
this(key, image, null);
}
private Face(String key, Image image, Face fallback) {
this.key = key;
this.image = image;
this.fallback = fallback;
}
public void setImage(Image image) {
this.image = image;
}
public Image getImage() {
if (image != null) {
return image;
}
if (fallback != null) {
return fallback.getImage();
}
return null;
}
public String getKey() {
return key;
}
}
private static class Group {
private ImageToggleButton currentButton;
public void handleClicked(ImageToggleButton button) {
if (currentButton != null) {
currentButton.setDown(false);
}
currentButton = button;
}
}
}
|