]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/AbstractGrabbable.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / element / handler / impl / AbstractGrabbable.java
diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/AbstractGrabbable.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/AbstractGrabbable.java
new file mode 100644 (file)
index 0000000..a235d34
--- /dev/null
@@ -0,0 +1,309 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.g2d.element.handler.impl;\r
+\r
+import java.awt.geom.Point2D;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.canvas.IMouseCaptureHandle;\r
+import org.simantics.g2d.diagram.participant.DiagramParticipant;\r
+import org.simantics.g2d.diagram.participant.ElementInteractor;\r
+import org.simantics.g2d.element.ElementUtils;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.g2d.element.handler.HandleMouseEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
+import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+import org.simantics.utils.datastructures.hints.IHintContext.MouseSpecificKeyOf;\r
+\r
+/**\r
+ * Base implementation for handlers that handle grabbable objects.\r
+ * \r
+ * TODO Esc button cancels grab\r
+ * \r
+ * @author Toni Kalajainen\r
+ */\r
+public abstract class AbstractGrabbable implements HandleMouseEvent {\r
+\r
+       private static final long serialVersionUID = -3620527648364111724L;\r
+       Double strayDistance;\r
+       protected int grabMouseButton = MouseEvent.LEFT_BUTTON;\r
+       \r
+       /**\r
+        * Create grabbable\r
+        * @param strayDistance stray distance or null for no limit\r
+        */\r
+       public AbstractGrabbable(Double strayDistance)\r
+       {\r
+               this.strayDistance = strayDistance;\r
+       }\r
+\r
+       public AbstractGrabbable()\r
+       {\r
+               this.strayDistance = 1000.0;\r
+       }\r
+       \r
+       @Override\r
+       public boolean handleMouseEvent(IElement e, ICanvasContext ctx, MouseEvent me) {\r
+               int     pointerId               = me.mouseId;\r
+               GrabInfo gi                             = getGrabInfo(e, ctx, pointerId);\r
+               \r
+               if ((me instanceof MouseClickEvent)||(me instanceof MouseDragBegin)) {\r
+                       return gi!=null;                                \r
+               }\r
+               \r
+               if ((me instanceof MouseMovedEvent)) {\r
+                       MouseMovedEvent mme = (MouseMovedEvent) me;\r
+                       if (gi==null) return false;\r
+\r
+                       gi.prevPosCanvas.setLocation( gi.dragPosCanvas );\r
+                       gi.prevPosControl.setLocation( gi.dragPosControl );\r
+                       gi.prevPosElement.setLocation( gi.dragPosElement );\r
+                       \r
+                       // Update drag positions\r
+                       gi.dragPosControl.setLocation(me.controlPosition);\r
+                       ElementUtils.controlToCanvasCoordinate(ctx, mme.controlPosition, gi.dragPosCanvas); \r
+                       ElementUtils.controlToElementCoordinate(e, ctx, mme.controlPosition, gi.dragPosElement);\r
+                       // Check if pointer has strayed too far, if so release grab\r
+                       double dist = gi.dragPosControl.distance(gi.grabPosControl);                    \r
+\r
+                       // Pointer has strayed too far -> release the pointer from the button\r
+                       if (dist>strayDistance)\r
+                       {\r
+                               releaseGrab(e, ctx, pointerId);\r
+                               onGrabCancel(gi, ctx);\r
+                               return true;\r
+                       }\r
+\r
+                       // Handle event\r
+                       onDrag(gi, ctx);\r
+                       // Consume event\r
+                       return true;\r
+               }\r
+               \r
+               // Mouse released\r
+               if (me instanceof MouseButtonReleasedEvent)\r
+               {\r
+                       MouseButtonEvent mbe = (MouseButtonEvent) me;\r
+                       if (mbe.button != grabMouseButton) return false;\r
+                       if (gi==null) return false;                     \r
+                       releaseGrab(e, ctx, pointerId);\r
+                       onRelease(gi, ctx);\r
+                       return true;\r
+               }\r
+               // Mouse pressed\r
+               if (me instanceof MouseButtonPressedEvent)\r
+               {\r
+                       MouseButtonEvent mbe = (MouseButtonEvent) me;\r
+                       if (mbe.button != grabMouseButton) return false;\r
+                       if (!onGrabCheck(e, ctx, pointerId, me.controlPosition))\r
+                               return false;\r
+                       gi = grabMouse(e, ctx, pointerId, me.controlPosition);\r
+                       onGrab(gi,ctx);\r
+                       return true;\r
+               }\r
+               \r
+               return false;\r
+       }\r
+       \r
+       /**\r
+        * Checks whether grab accepted\r
+        * @param e element\r
+        * @param pickPos pick position in element coordinates \r
+        * @return true if position is grabbable\r
+        */\r
+       protected abstract boolean onGrabCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos);\r
+       \r
+       protected abstract void onGrab(GrabInfo gi, ICanvasContext ctx);\r
+\r
+       /**\r
+        * Event when grab is released (and not canceled)\r
+        * Invoked after grab is released.\r
+        * @param gi\r
+        * @param ctx\r
+        */\r
+       protected abstract void onRelease(GrabInfo gi, ICanvasContext ctx);\r
+       \r
+       protected abstract void onDrag(GrabInfo gi, ICanvasContext ctx);\r
+       \r
+       /**\r
+        * Event notified when grab is canceled. Canceling occurs automatically\r
+        * when mouse strays too far and when user sends cancel command (presses esc) \r
+        * \r
+        * @param e\r
+        * @param grabPos\r
+        */\r
+       protected abstract void onGrabCancel(GrabInfo gi, ICanvasContext ctx);\r
+       \r
+       protected void cancelGrab() {           \r
+       }\r
+               \r
+       public static class GrabInfo {\r
+               // Grabbed element\r
+               public IElement e;\r
+               // grabbing pointer\r
+               public int pointerId;\r
+               // Grab position\r
+               public Point2D grabPosControl = new Point2D.Double();\r
+               public Point2D grabPosCanvas = new Point2D.Double();\r
+               public Point2D grabPosElement = new Point2D.Double();\r
+               // Drag position\r
+               public Point2D dragPosControl = new Point2D.Double();  \r
+               public Point2D dragPosCanvas  = new Point2D.Double();\r
+               public Point2D dragPosElement = new Point2D.Double();\r
+               // Prev position\r
+               public Point2D prevPosControl = new Point2D.Double();  \r
+               public Point2D prevPosCanvas  = new Point2D.Double();\r
+               public Point2D prevPosElement = new Point2D.Double();\r
+               // Capture handle\r
+               private IMouseCaptureHandle hnd;\r
+       }               \r
+\r
+       /**\r
+        * Remove GrabInfo object\r
+        * @param e\r
+        * @param ctx\r
+        * @param pointerId\r
+        */\r
+       private void removeGrabInfo(IElement e, ICanvasContext ctx, int pointerId)\r
+       {\r
+               DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
+               Key key = new MouseSpecificKeyOf(pointerId, GrabInfo.class);\r
+               dp.removeElementHint(e, key);\r
+       }\r
+       \r
+       /**\r
+        * Set GrabInfo object\r
+        * @param e\r
+        * @param ctx\r
+        * @param pointerId\r
+        * @param gi\r
+        */\r
+       private void setGrabInfo(IElement e, ICanvasContext ctx, int pointerId, GrabInfo gi)\r
+       {\r
+               DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
+               Key key = new MouseSpecificKeyOf(pointerId, GrabInfo.class);\r
+               dp.setElementHint(e, key, gi);\r
+               \r
+       }\r
+       \r
+       /**\r
+        * Get GrabInfo Object\r
+        * @param e\r
+        * @param ctx\r
+        * @param pointerId\r
+        * @return\r
+        */\r
+       private GrabInfo getGrabInfo(IElement e, ICanvasContext ctx, int pointerId)\r
+       {\r
+               DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
+               Key key = new MouseSpecificKeyOf(pointerId, GrabInfo.class);            \r
+               return dp.getElementHint(e, key);\r
+       }\r
+       \r
+       /**\r
+        * Get all pointer grabs\r
+        * @return\r
+        */\r
+       protected Map<Integer, GrabInfo> getGrabs(IElement e, ICanvasContext ctx)\r
+       {\r
+               DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
+               Map<Key, Object> map = dp.getElementHints(e);\r
+               if (map==null) return null;\r
+               Map<Integer, GrabInfo> result = new HashMap<Integer, GrabInfo>();\r
+               for (Entry<Key, Object> entry : map.entrySet())\r
+               {\r
+                       if (!(entry.getValue() instanceof GrabInfo)) continue;\r
+                       GrabInfo gi = (GrabInfo) entry.getValue();\r
+                       result.put(gi.pointerId, gi);\r
+               }\r
+               return result;\r
+       }       \r
+       \r
+       protected int getGrabCount(IElement e, ICanvasContext ctx)\r
+       {\r
+               DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
+               Map<Key, Object> map = dp.getElementHints(e);\r
+               if (map==null) return 0;\r
+               int result = 0;\r
+               for (Entry<Key, Object> entry : map.entrySet())\r
+               {\r
+                       if (!(entry.getValue() instanceof GrabInfo)) continue;\r
+                       result ++;\r
+               }\r
+               return result;\r
+       }\r
+       \r
+       /**\r
+        * Release grab of a pointer\r
+        * @param e\r
+        * @param ctx\r
+        * @param pointerId\r
+        */\r
+       protected void releaseGrab(IElement e, ICanvasContext ctx, int pointerId)\r
+       {\r
+               GrabInfo gi = getGrabInfo(e, ctx, pointerId);\r
+               if (gi==null) return;\r
+               gi.hnd.release();\r
+               removeGrabInfo(e, ctx, pointerId);\r
+       }\r
+       \r
+       /**\r
+        * Grab a pointer\r
+        * @param e\r
+        * @param ctx\r
+        * @param pointerId\r
+        * @param grabPointControl\r
+        * @return\r
+        */\r
+       private GrabInfo grabMouse(IElement e, ICanvasContext ctx, int pointerId, Point2D grabPointControl)\r
+       {\r
+               // Release previous capture, if exists\r
+               releaseGrab(e, ctx, pointerId);         \r
+               \r
+               ElementInteractor ei = ctx.getSingleItem(ElementInteractor.class);\r
+               IMouseCaptureHandle hnd = ei.captureMouse(e, pointerId);\r
+               if (hnd == null) return null;\r
+\r
+               Point2D grabPointCanvas = ElementUtils.controlToCanvasCoordinate(ctx, grabPointControl, new Point2D.Double());\r
+               Point2D grabPointElement = ElementUtils.controlToElementCoordinate(e, ctx, grabPointControl, new Point2D.Double());\r
+               \r
+               GrabInfo gi = new GrabInfo();\r
+               gi.e = e;\r
+               gi.hnd = hnd;\r
+               gi.pointerId = pointerId;\r
+               gi.grabPosControl.setLocation(grabPointControl);\r
+               gi.grabPosCanvas.setLocation(grabPointCanvas);\r
+               gi.grabPosElement.setLocation(grabPointElement);\r
+               \r
+               gi.dragPosControl.setLocation(grabPointControl);\r
+               gi.dragPosCanvas.setLocation(grabPointCanvas);\r
+               gi.dragPosElement.setLocation(grabPointElement);\r
+                               \r
+               gi.prevPosControl.setLocation(grabPointControl);\r
+               gi.prevPosCanvas.setLocation(grabPointCanvas);\r
+               gi.prevPosElement.setLocation(grabPointElement);\r
+               \r
+               setGrabInfo(e, ctx, pointerId, gi);\r
+               \r
+               return gi;\r
+       }       \r
+\r
+}\r