/* * Copyright 2010 Daniel Kurka * * 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.googlecode.mgwt.ui.client.widget.input.checkbox; import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Touch; import com.google.gwt.editor.client.IsEditor; import com.google.gwt.editor.client.LeafValueEditor; import com.google.gwt.editor.client.adapters.TakesValueEditor; import com.google.gwt.event.dom.client.TouchCancelEvent; import com.google.gwt.event.dom.client.TouchEndEvent; import com.google.gwt.event.dom.client.TouchMoveEvent; import com.google.gwt.event.dom.client.TouchStartEvent; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.uibinder.client.UiFactory; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.HasValue; import com.googlecode.mgwt.dom.client.event.touch.TouchHandler; import com.googlecode.mgwt.ui.client.MGWT; import com.googlecode.mgwt.ui.client.util.CssUtil; import com.googlecode.mgwt.ui.client.widget.touch.TouchWidget; /** * A checkbox widget. */ public class MCheckBox extends TouchWidget implements HasValue<Boolean>, IsEditor<LeafValueEditor<Boolean>> { public static final MCheckBoxAppearance DEFAULT_APPEARANCE = GWT.create(MCheckBoxAppearance.class); private final class TouchHandlerImplementation implements TouchHandler { private int x_start; private int x_min; private int x_max; private int offset; private boolean moved; private int now_x; @Override public void onTouchCancel(TouchCancelEvent event) { if (isReadOnly()) { return; } event.stopPropagation(); event.preventDefault(); if (MGWT.getFormFactor().isDesktop()) { DOM.releaseCapture(getElement()); } setValue(getValue()); } @Override public void onTouchEnd(TouchEndEvent event) { if (isReadOnly()) { return; } event.stopPropagation(); event.preventDefault(); if (MGWT.getFormFactor().isDesktop()) { DOM.releaseCapture(getElement()); } if (!moved) { setValue(!getValue()); } else { setValue(now_x >= x_start); } } @Override public void onTouchMove(TouchMoveEvent event) { if (isReadOnly()) { return; } event.stopPropagation(); event.preventDefault(); Touch touch = event.getTouches().get(0); now_x = touch.getClientX(); if (!moved) { if (Math.abs(now_x - x_start) < appearance.css().DRAG_DEADZONE()) { return; } } moved = true; int translate_x = now_x - x_start; if (translate_x < x_min) { return; } if (translate_x > x_max) { return; } translate(translate_x + offset); } @Override public void onTouchStart(TouchStartEvent event) { if (isReadOnly()) { return; } event.stopPropagation(); event.preventDefault(); if (MGWT.getFormFactor().isDesktop()) { DOM.setCapture(getElement()); } Touch touch = event.getTouches().get(0); x_start = touch.getClientX(); moved = false; if (value) { x_min = appearance.css().CONTAINER_MIN_ON(); x_max = appearance.css().CONTAINER_MAX_ON(); offset = appearance.css().CONTAINER_OFFSET_ON(); } else { x_min = appearance.css().CONTAINER_MIN_OFF(); x_max = appearance.css().CONTAINER_MAX_OFF(); offset = appearance.css().CONTAINER_OFFSET_OFF(); } } } private boolean value; @UiField public Element on; @UiField public Element middle; @UiField public Element off; private LeafValueEditor<Boolean> editor; private boolean readonly; private MCheckBoxAppearance appearance; public MCheckBox() { this(DEFAULT_APPEARANCE); } public MCheckBox(MCheckBoxAppearance appearance) { this.appearance = appearance; setElement(appearance.uiBinder().createAndBindUi(this)); addTouchHandler(new TouchHandlerImplementation()); setValue(true, false); } @Override public com.google.gwt.event.shared.HandlerRegistration addValueChangeHandler(ValueChangeHandler<Boolean> handler) { return addHandler(handler, ValueChangeEvent.getType()); } @Override public Boolean getValue() { return value; } @Override public void setValue(Boolean value) { setValue(value, true); } @Override public void setValue(Boolean value, boolean fireEvents) { if (value == null) { throw new IllegalArgumentException("value can not be null"); } boolean oldValue = this.value; this.value = value; clearStyles(); if (value) { addStyleName(appearance.css().checked()); removeStyleName(appearance.css().notChecked()); } else { addStyleName(appearance.css().notChecked()); removeStyleName(appearance.css().checked()); } if (fireEvents){ ValueChangeEvent.fireIfNotEqual(this, oldValue, this.value); } } /** * Should this check box be rendered as important * * @param important true to render the check box as important */ public void setImportant(boolean important) { if (important) { addStyleName(appearance.css().important()); } else { removeStyleName(appearance.css().important()); } } @Override public LeafValueEditor<Boolean> asEditor() { if (editor == null) { editor = TakesValueEditor.of(this); } return editor; } /** * Should the checkbox be readonly * * @param readonly true to be read only */ public void setReadOnly(boolean readonly) { this.readonly = readonly; } /** * Is the checkbox currently read only? * * @return true if the checkbox is readonly */ public boolean isReadOnly() { return readonly; } @UiFactory public MCheckBoxAppearance getAppearance() { return appearance; } private void translate(int x) { CssUtil.translate(on, x, 0); CssUtil.translate(middle, x, 0); CssUtil.translate(off, x, 0); } private void clearStyles() { middle.setAttribute("style", ""); on.setAttribute("style", ""); off.setAttribute("style", ""); } }