/** * Copyright 2010 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 org.waveprotocol.wave.client.widget.button; import org.waveprotocol.wave.client.widget.button.ButtonDisplay.ButtonState; /** * Implements the logic for buttons that only have one associated action, that * is, buttons that immediately return to their original state when they are * clicked. * */ public class ClickButton implements UniversalButton<ClickButtonController> { /** * The visual representation of this button. */ protected ButtonDisplay buttonDisplay = null; /** * Is the mouse currently over the button? */ protected boolean isMouseOver = false; /** * Is the mouse button currently down? */ protected boolean isMouseDown = false; /** * Is this button disabled? */ protected boolean isDisabled = false; /** * Listener for click events (provided by users to make the button do * something). */ protected ClickButtonListener clickListener; /** * Listener for click-when-disabled events. */ protected ClickWhenDisabledListener clickWhenDisabledListener; /** * Implementation of the public interface for controlling this button. */ protected ClickButtonController controller = new ClickButtonController() { @Override public void setClickButtonListener(ClickButtonListener listener) { clickListener = listener; } @Override public void setClickWhenDisabledListener(ClickWhenDisabledListener listener) { clickWhenDisabledListener = listener; } @Override public void setDisabled(boolean isDisabled) { if (ClickButton.this.isDisabled != isDisabled) { ClickButton.this.isDisabled = isDisabled; updateState(); } } @Override public void setTooltip(String tooltip) { ClickButton.this.buttonDisplay.setTooltip(tooltip); } @Override public void setText(String text) { ClickButton.this.buttonDisplay.setText(text); } }; /** * Listener for click events from a button. * */ public interface ClickButtonListener { /** * Called when a click event occurs on a button. */ void onClick(); } /** * Listener for click events from a button when it's disabled. * * TODO(kalman): Put in ClickButtonListener, provide vacuous implementation. */ public interface ClickWhenDisabledListener { void onClickWhenDisabled(); } /** * Create the listener on object creation so it can be used later */ protected MouseListener mouseListener = new MouseListener() { /** {@inheritDoc} */ public void onMouseDown() { isMouseDown = true; updateState(); } /** {@inheritDoc} */ public void onMouseEnter() { isMouseOver = true; updateState(); } /** {@inheritDoc} */ public void onMouseLeave() { isMouseOver = false; isMouseDown = false; updateState(); } /** {@inheritDoc} */ public void onMouseUp() { isMouseDown = false; updateState(); } /** {@inheritDoc} */ public void onClick() { if (isDisabled) { if (clickWhenDisabledListener != null) { clickWhenDisabledListener.onClickWhenDisabled(); } return; } if (clickListener != null) { clickListener.onClick(); } } }; public ClickButton(ButtonDisplay button) { setButtonDisplay(button); button.setUiListener(getUiEventListener()); } public ClickButton() { } /** {@inheritDoc} */ public MouseListener getUiEventListener() { return mouseListener; } /** * Updates the visual state of the button to reflect the current logical * state. */ protected void updateState() { if (isDisabled) { setState(ButtonState.DISABLED); return; } if (isMouseOver) { setState(isMouseDown ? ButtonDisplay.ButtonState.DOWN : ButtonDisplay.ButtonState.HOVER); } else { setState(ButtonDisplay.ButtonState.NORMAL); } } /** * Sets a new state for this button and notifies the display. * * @param state The new state for this button. */ private void setState(ButtonDisplay.ButtonState state) { // NOTE(patcoleman): Does not check here to see whether the new state is the same // as the current state - possible optimisation can be added to return on NOOP? i.e. // if(newState.equals(state)) return; if (buttonDisplay != null) { buttonDisplay.setState(state); } } /** {@inheritDoc} */ public void setButtonDisplay(ButtonDisplay controlledButton) { this.buttonDisplay = controlledButton; updateState(); } /** * @param listener Callback to be fired when the button is clicked. */ public void setClickButtonListener(ClickButtonListener listener) { this.clickListener = listener; } /** {@inheritDoc} */ public ClickButtonController getController() { return controller; } public static void attachListenerTo(ButtonDisplay view, ClickButton.ClickButtonListener listener) { ClickButton buttonLogic = new ClickButton(); buttonLogic.setClickButtonListener(listener); buttonLogic.setButtonDisplay(view); view.setUiListener(buttonLogic.getUiEventListener()); } }