package org.iplantc.phyloviewer.client.events;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.iplantc.phyloviewer.shared.math.Vector2;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.dom.client.HandlesAllMouseEvents;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseWheelEvent;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.Widget;
public class BaseMouseHandler extends HandlesAllMouseEvents implements ClickHandler, DoubleClickHandler
{
/** The largest button code returned by event.getNativeButton() */
public static final int MAX_BUTTON = 4;
private Widget targetWidget;
/** Current mousedown events, indexed by mouse button. Null if button is up. */
private SavedMouseEvent[] mouseDownEvents = new SavedMouseEvent[MAX_BUTTON + 1];
private SavedMouseEvent lastMouseMove = null;
private double dragThreshold = 10;
private boolean[] isDragging = new boolean[MAX_BUTTON + 1];
public BaseMouseHandler(Widget targetWidget)
{
this.targetWidget = targetWidget;
}
@Override
public void onClick(ClickEvent event)
{
Logger.getLogger("").log(Level.FINEST, "Click button: " + event.getNativeButton());
}
@Override
public void onDoubleClick(DoubleClickEvent event)
{
Logger.getLogger("").log(Level.FINEST, "DoubleClick button: " + event.getNativeButton());
}
@Override
public void onMouseDown(MouseDownEvent event)
{
Logger.getLogger("").log(Level.FINEST, "MouseDown button: " + event.getNativeButton());
event.preventDefault();
if (targetWidget instanceof Focusable)
{
/*
* the preventDefault above is necessary to prevent the mouse cursor changing to a text
* selection cursor when dragging, but it also prevents the widget from getting focus, so I
* set that here.
*/
((Focusable)targetWidget).setFocus(true);
}
int button = event.getNativeButton();
mouseDownEvents[button] = new SavedMouseEvent(event);
}
@Override
public void onMouseUp(MouseUpEvent event)
{
Logger.getLogger("").log(Level.FINEST, "MouseUp button: " + event.getNativeButton());
int button = event.getNativeButton();
mouseDownEvents[button] = null;
isDragging[button] = false;
}
@Override
public void onMouseMove(MouseMoveEvent event)
{
lastMouseMove = new SavedMouseEvent(event);
//update dragging status, if button is down and hasn't already been marked as dragging
for (int button = 0; button < mouseDownEvents.length; button++)
{
if (!isDragging[button] && mouseDownEvents[button] != null)
{
if (isPastDragThreshold(button))
{
isDragging[button] = true;
}
}
}
}
@Override
public void onMouseOut(MouseOutEvent event)
{
Logger.getLogger("").log(Level.FINEST, "MouseOut button: " + event.getNativeButton());
}
@Override
public void onMouseOver(MouseOverEvent event)
{
Logger.getLogger("").log(Level.FINEST, "MouseOver button: " + event.getNativeButton());
/*
* MouseOverEvent.getNativeButton() currently returns 1 even if no button is down (for many
* browsers), so there's no good way to test if the user released the button while the mouse was
* outside the view. So, to err on the side of avoiding spurious actions, I'm going to assume
* all buttons were released.
*/
clearMouseDown();
}
@Override
public void onMouseWheel(MouseWheelEvent event)
{
Logger.getLogger("").log(Level.FINEST, "MouseWheel delta: " + event.getDeltaY());
}
public SavedMouseEvent getCurrentMouseDownEvent(int button)
{
if (button > MAX_BUTTON || button < 0)
{
return null;
}
else
{
return mouseDownEvents[button];
}
}
public SavedMouseEvent getLastMouseMove()
{
return lastMouseMove;
}
public Vector2 getLastMousePosition()
{
if (lastMouseMove == null)
{
return null;
}
return lastMouseMove.getLocation();
}
public boolean isDragging(int button)
{
return isDragging[button];
}
private boolean isPastDragThreshold(int button)
{
boolean isPast = false;
SavedMouseEvent downEvent = getCurrentMouseDownEvent(button);
if (downEvent != null)
{
Vector2 v = lastMouseMove.getLocation().subtract(downEvent.getLocation());
isPast = v.length() > dragThreshold;
}
return isPast;
}
private void clearMouseDown()
{
mouseDownEvents = new SavedMouseEvent[MAX_BUTTON + 1];
isDragging = new boolean[MAX_BUTTON + 1];
}
/** MouseDownEvents are killed by GWT after they are handled. This class stores some details of a MouseDownEvent for later use. */
public class SavedMouseEvent
{
public final int nativeButton;
public final int x;
public final int y;
public final boolean isAltKeyDown;
public final boolean isControlKeyDown;
public final boolean isMetaKeyDown;
public final boolean isShiftKeyDown;
@SuppressWarnings("unchecked")
public SavedMouseEvent(MouseEvent event)
{
nativeButton = event.getNativeButton();
x = event.getX();
y = event.getY();
isAltKeyDown = event.isAltKeyDown();
isControlKeyDown = event.isControlKeyDown();
isMetaKeyDown = event.isMetaKeyDown();
isShiftKeyDown = event.isShiftKeyDown();
}
public Vector2 getLocation()
{
return new Vector2(x, y);
}
}
}