package org.iplantc.phyloviewer.client.events; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; import org.iplantc.phyloviewer.client.tree.viewer.DetailView; import org.iplantc.phyloviewer.shared.math.Vector2; import org.iplantc.phyloviewer.shared.model.INode; import org.iplantc.phyloviewer.shared.render.RenderPreferences; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.event.dom.client.DoubleClickEvent; import com.google.gwt.event.dom.client.MouseMoveEvent; import com.google.gwt.event.dom.client.MouseUpEvent; import com.google.gwt.event.dom.client.MouseWheelEvent; public class NavigationMouseHandler extends BaseMouseHandler { // TODO listen for tree changes on the view and clear nodeHistory and currentNodeShown private final DetailView view; private Stack<INode> nodeHistory = new Stack<INode>(); // tried LinkedList here and the compiler // complained that LinkedList.push() and // LinkedList.pop() are undefined... private INode currentNodeShown = null; public NavigationMouseHandler(DetailView view) { super(view); this.view = view; } @Override public void onMouseUp(MouseUpEvent event) { SavedMouseEvent downEvent = super.getCurrentMouseDownEvent(NativeEvent.BUTTON_LEFT); //getting mouse down data before super.onMouseUp(event) clears it boolean wasDragging = isDragging(NativeEvent.BUTTON_LEFT); super.onMouseUp(event); if (wasDragging) { handleDragFinished(downEvent, new SavedMouseEvent(event)); } else { handleClick(downEvent, new SavedMouseEvent(event)); } } @Override public void onMouseMove(MouseMoveEvent event) { Vector2 event1 = super.getLastMousePosition(); // getting prev position before // super.onMouseMove(event) updates it super.onMouseMove(event); Vector2 event0 = super.getLastMousePosition(); if(isDragging(NativeEvent.BUTTON_LEFT) && event0 != null && event1 != null) { Vector2 p0 = view.getPositionInLayoutSpace(event0); Vector2 p1 = view.getPositionInLayoutSpace(event1); double x = p0.getX() - p1.getX(); double y = p0.getY() - p1.getY(); view.pan(x, y); } } @Override public void onMouseWheel(MouseWheelEvent event) { super.onMouseWheel(event); double amount = -event.getDeltaY() / 10.0; amount = Math.pow(2, amount); view.zoom(amount); } @Override public void onDoubleClick(DoubleClickEvent event) { super.onDoubleClick(event); // On Mac, control + left click shows the context menu. Also check for the 'meta' (apple) key. if (event.isControlKeyDown() || event.isMetaKeyDown()) { //toggle collapsed INode node = view.getNodeAt(event.getX(), event.getY()); RenderPreferences renderPreferences = view.getRenderPreferences(); boolean isCollapsed = renderPreferences.isCollapsed(node); renderPreferences.setCollapsed(node, !isCollapsed); view.requestRender(); } else { //show the clicked node INode node = view.getNodeAt(event.getX(), event.getY()); nodeHistory.push(currentNodeShown); // Only show if the node is not null. // Otherwise, if the user double clicks on the background, the viewer zooms to the root. // (I don't think that behavior is expected.) if(node != null) { show(node); } } } private void show(INode node) { if(node == null) { node = view.getTree().getRootNode(); } view.zoomToFitSubtree(node); currentNodeShown = node; } private void gestureX(double dx) { Logger.getLogger("").log(Level.FINEST, "gestureX() " + dx); if(dx > 0) { // TODO pan right one 'step'. Where to? Keep forward history? Go to highest child? } else { INode nodeToShow = null; if(!nodeHistory.isEmpty()) { nodeToShow = nodeHistory.pop(); } show(nodeToShow); } } private void gestureY(double dy) { Logger.getLogger("").log(Level.FINEST, "gestureY() " + dy); // TODO? } /** * This gets called from onMouseUp when it decides the mouseup event is not a drag. * * @param downEvent * @param savedMouseEvent */ private void handleClick(SavedMouseEvent downEvent, SavedMouseEvent upEvent) { /* * currently a single click does nothing. Note that this method would get called twice on a * double click (in addition to the onDoubleClick()) */ } private void handleDragFinished(SavedMouseEvent downEvent, SavedMouseEvent upEvent) { Vector2 v = upEvent.getLocation().subtract(downEvent.getLocation()); if(Math.abs(v.getX()) > Math.abs(v.getY())) { gestureX(v.getX()); } else { gestureY(v.getY()); } } }