/**
* Copyright 2011 The ForPlay Authors
*
* 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 forplay.html;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import forplay.core.ForPlay;
import forplay.core.Mouse;
class HtmlMouse extends HtmlInput implements Mouse {
private Listener listener;
boolean inDragSequence = false; // true when we are in a drag sequence (after mouse down but before mouse up)
HtmlMouse(final Element rootElement) {
// capture mouse down on the root element, only.
captureEvent(rootElement, "mousedown", new EventHandler() {
@Override
public void handleEvent(NativeEvent evt) {
if (listener != null) {
inDragSequence = true;
listener.onMouseDown(
new ButtonEvent.Impl(ForPlay.currentTime(), getRelativeX(evt, rootElement),
getRelativeY(evt, rootElement), getMouseButton(evt)));
}
}
});
// capture mouse up anywhere on the page as long as we are in a drag sequence
capturePageEvent("mouseup", new EventHandler() {
@Override
public void handleEvent(NativeEvent evt) {
if (listener != null && inDragSequence) {
inDragSequence = false;
listener.onMouseUp(
new ButtonEvent.Impl(ForPlay.currentTime(), getRelativeX(evt, rootElement),
getRelativeY(evt, rootElement), getMouseButton(evt)));
}
}
});
// capture mouse move anywhere on the page that fires only if we are in a drag sequence
capturePageEvent("mousemove", new EventHandler() {
@Override
public void handleEvent(NativeEvent evt) {
if (listener != null && inDragSequence) {
listener.onMouseMove(
new MotionEvent.Impl(ForPlay.currentTime(), getRelativeX(evt, rootElement),
getRelativeY(evt, rootElement)));
}
}
});
// capture mouse move on the root element that fires only if we are not in a drag sequence
// (the page-level event listener will handle the firing when we are in a drag sequence)
captureEvent(rootElement, "mousemove", new EventHandler() {
@Override
public void handleEvent(NativeEvent evt) {
if (listener != null && !inDragSequence) {
listener.onMouseMove(
new MotionEvent.Impl(ForPlay.currentTime(), getRelativeX(evt, rootElement),
getRelativeY(evt, rootElement)));
}
}
});
captureEvent(rootElement, getMouseWheelEvent(), new EventHandler() {
@Override
public void handleEvent(NativeEvent evt) {
if (listener != null) {
// We need to prevent the default so that the page doesn't scroll.
// The user can still scroll if the mouse isn't over the root element.
evt.preventDefault();
listener.onMouseWheelScroll(
new WheelEvent.Impl(ForPlay.currentTime(), getMouseWheelVelocity(evt)));
}
}
});
}
@Override
public void setListener(Listener listener) {
this.listener = listener;
}
/**
* Return the mouse wheel velocity for the event
*/
private static native float getMouseWheelVelocity(NativeEvent evt) /*-{
var delta = 0.0;
var useragent = navigator.userAgent.toLowerCase();
if (useragent.indexOf('firefox') != -1) {
if (useragent.indexOf('mac') != -1) {
delta = 1.0 * evt.detail;
} else {
delta = 1.0 * evt.detail/3;
}
} else if (useragent.indexOf('opera') != -1) {
if (useragent.indexOf('linux') != -1) {
delta = -1.0 * evt.wheelDelta/80;
} else {
// on mac
delta = -1.0 * evt.wheelDelta/40;
}
} else if (useragent.indexOf('chrome') != -1 ||
useragent.indexOf('safari') != -1) {
delta = -1.0 * evt.wheelDelta/120;
// handle touchpad for chrome
if (Math.abs(delta) < 1) {
if (useragent.indexOf('win') != -1) {
delta = -1.0 * evt.wheelDelta;
} else if (useragent.indexOf('mac') != -1) {
delta = -1.0 * evt.wheelDelta/3;
}
}
} else {
delta = evt.detail ? evt.detail : -1 * evt.wheelDelta / 40;
}
return delta;
}-*/;
/**
* Return the appropriate mouse wheel event name for the current browser
*
* @return return the mouse wheel event name for the current browser
*/
protected static native String getMouseWheelEvent() /*-{
if (navigator.userAgent.toLowerCase().indexOf('firefox') != -1) {
return "DOMMouseScroll";
} else {
return "mousewheel";
}
}-*/;
/**
* Return the {@link Mouse} button given a {@link NativeEvent}
*
* @param evt Native event
* @return {@link Mouse} button corresponding to the event
*/
protected static int getMouseButton(NativeEvent evt) {
switch (evt.getButton()) {
case (NativeEvent.BUTTON_LEFT):
return Mouse.BUTTON_LEFT;
case (NativeEvent.BUTTON_MIDDLE):
return Mouse.BUTTON_MIDDLE;
case (NativeEvent.BUTTON_RIGHT):
return Mouse.BUTTON_RIGHT;
default:
return evt.getButton();
}
}
}