]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/AbstractGrabbable.java
Sync git svn branch with SVN repository r33324.
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / element / handler / impl / AbstractGrabbable.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.g2d.element.handler.impl;\r
13 \r
14 import java.awt.geom.Point2D;\r
15 import java.util.HashMap;\r
16 import java.util.Map;\r
17 import java.util.Map.Entry;\r
18 \r
19 import org.simantics.g2d.canvas.ICanvasContext;\r
20 import org.simantics.g2d.canvas.IMouseCaptureHandle;\r
21 import org.simantics.g2d.diagram.participant.DiagramParticipant;\r
22 import org.simantics.g2d.diagram.participant.ElementInteractor;\r
23 import org.simantics.g2d.element.ElementUtils;\r
24 import org.simantics.g2d.element.IElement;\r
25 import org.simantics.g2d.element.handler.HandleMouseEvent;\r
26 import org.simantics.scenegraph.g2d.events.MouseEvent;\r
27 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonEvent;\r
28 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
29 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;\r
30 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent;\r
31 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
32 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
33 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
34 import org.simantics.utils.datastructures.hints.IHintContext.MouseSpecificKeyOf;\r
35 \r
36 /**\r
37  * Base implementation for handlers that handle grabbable objects.\r
38  * \r
39  * TODO Esc button cancels grab\r
40  * \r
41  * @author Toni Kalajainen\r
42  */\r
43 public abstract class AbstractGrabbable implements HandleMouseEvent {\r
44 \r
45         private static final long serialVersionUID = -3620527648364111724L;\r
46         Double strayDistance;\r
47         protected int grabMouseButton = MouseEvent.LEFT_BUTTON;\r
48         \r
49         /**\r
50          * Create grabbable\r
51          * @param strayDistance stray distance or null for no limit\r
52          */\r
53         public AbstractGrabbable(Double strayDistance)\r
54         {\r
55                 this.strayDistance = strayDistance;\r
56         }\r
57 \r
58         public AbstractGrabbable()\r
59         {\r
60                 this.strayDistance = 1000.0;\r
61         }\r
62         \r
63         @Override\r
64         public boolean handleMouseEvent(IElement e, ICanvasContext ctx, MouseEvent me) {\r
65                 int     pointerId               = me.mouseId;\r
66                 GrabInfo gi                             = getGrabInfo(e, ctx, pointerId);\r
67                 \r
68                 if ((me instanceof MouseClickEvent)||(me instanceof MouseDragBegin)) {\r
69                         return gi!=null;                                \r
70                 }\r
71                 \r
72                 if ((me instanceof MouseMovedEvent)) {\r
73                         MouseMovedEvent mme = (MouseMovedEvent) me;\r
74                         if (gi==null) return false;\r
75 \r
76                         gi.prevPosCanvas.setLocation( gi.dragPosCanvas );\r
77                         gi.prevPosControl.setLocation( gi.dragPosControl );\r
78                         gi.prevPosElement.setLocation( gi.dragPosElement );\r
79                         \r
80                         // Update drag positions\r
81                         gi.dragPosControl.setLocation(me.controlPosition);\r
82                         ElementUtils.controlToCanvasCoordinate(ctx, mme.controlPosition, gi.dragPosCanvas); \r
83                         ElementUtils.controlToElementCoordinate(e, ctx, mme.controlPosition, gi.dragPosElement);\r
84                         // Check if pointer has strayed too far, if so release grab\r
85                         double dist = gi.dragPosControl.distance(gi.grabPosControl);                    \r
86 \r
87                         // Pointer has strayed too far -> release the pointer from the button\r
88                         if (dist>strayDistance)\r
89                         {\r
90                                 releaseGrab(e, ctx, pointerId);\r
91                                 onGrabCancel(gi, ctx);\r
92                                 return true;\r
93                         }\r
94 \r
95                         // Handle event\r
96                         onDrag(gi, ctx);\r
97                         // Consume event\r
98                         return true;\r
99                 }\r
100                 \r
101                 // Mouse released\r
102                 if (me instanceof MouseButtonReleasedEvent)\r
103                 {\r
104                         MouseButtonEvent mbe = (MouseButtonEvent) me;\r
105                         if (mbe.button != grabMouseButton) return false;\r
106                         if (gi==null) return false;                     \r
107                         releaseGrab(e, ctx, pointerId);\r
108                         onRelease(gi, ctx);\r
109                         return true;\r
110                 }\r
111                 // Mouse pressed\r
112                 if (me instanceof MouseButtonPressedEvent)\r
113                 {\r
114                         MouseButtonEvent mbe = (MouseButtonEvent) me;\r
115                         if (mbe.button != grabMouseButton) return false;\r
116                         if (!onGrabCheck(e, ctx, pointerId, me.controlPosition))\r
117                                 return false;\r
118                         gi = grabMouse(e, ctx, pointerId, me.controlPosition);\r
119                         onGrab(gi,ctx);\r
120                         return true;\r
121                 }\r
122                 \r
123                 return false;\r
124         }\r
125         \r
126         /**\r
127          * Checks whether grab accepted\r
128          * @param e element\r
129          * @param pickPos pick position in element coordinates \r
130          * @return true if position is grabbable\r
131          */\r
132         protected abstract boolean onGrabCheck(IElement e, ICanvasContext ctx, int pointerId, Point2D pickPos);\r
133         \r
134         protected abstract void onGrab(GrabInfo gi, ICanvasContext ctx);\r
135 \r
136         /**\r
137          * Event when grab is released (and not canceled)\r
138          * Invoked after grab is released.\r
139          * @param gi\r
140          * @param ctx\r
141          */\r
142         protected abstract void onRelease(GrabInfo gi, ICanvasContext ctx);\r
143         \r
144         protected abstract void onDrag(GrabInfo gi, ICanvasContext ctx);\r
145         \r
146         /**\r
147          * Event notified when grab is canceled. Canceling occurs automatically\r
148          * when mouse strays too far and when user sends cancel command (presses esc) \r
149          * \r
150          * @param e\r
151          * @param grabPos\r
152          */\r
153         protected abstract void onGrabCancel(GrabInfo gi, ICanvasContext ctx);\r
154         \r
155         protected void cancelGrab() {           \r
156         }\r
157                 \r
158         public static class GrabInfo {\r
159                 // Grabbed element\r
160                 public IElement e;\r
161                 // grabbing pointer\r
162                 public int pointerId;\r
163                 // Grab position\r
164                 public Point2D grabPosControl = new Point2D.Double();\r
165                 public Point2D grabPosCanvas = new Point2D.Double();\r
166                 public Point2D grabPosElement = new Point2D.Double();\r
167                 // Drag position\r
168                 public Point2D dragPosControl = new Point2D.Double();  \r
169                 public Point2D dragPosCanvas  = new Point2D.Double();\r
170                 public Point2D dragPosElement = new Point2D.Double();\r
171                 // Prev position\r
172                 public Point2D prevPosControl = new Point2D.Double();  \r
173                 public Point2D prevPosCanvas  = new Point2D.Double();\r
174                 public Point2D prevPosElement = new Point2D.Double();\r
175                 // Capture handle\r
176                 private IMouseCaptureHandle hnd;\r
177         }               \r
178 \r
179         /**\r
180          * Remove GrabInfo object\r
181          * @param e\r
182          * @param ctx\r
183          * @param pointerId\r
184          */\r
185         private void removeGrabInfo(IElement e, ICanvasContext ctx, int pointerId)\r
186         {\r
187                 DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
188                 Key key = new MouseSpecificKeyOf(pointerId, GrabInfo.class);\r
189                 dp.removeElementHint(e, key);\r
190         }\r
191         \r
192         /**\r
193          * Set GrabInfo object\r
194          * @param e\r
195          * @param ctx\r
196          * @param pointerId\r
197          * @param gi\r
198          */\r
199         private void setGrabInfo(IElement e, ICanvasContext ctx, int pointerId, GrabInfo gi)\r
200         {\r
201                 DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
202                 Key key = new MouseSpecificKeyOf(pointerId, GrabInfo.class);\r
203                 dp.setElementHint(e, key, gi);\r
204                 \r
205         }\r
206         \r
207         /**\r
208          * Get GrabInfo Object\r
209          * @param e\r
210          * @param ctx\r
211          * @param pointerId\r
212          * @return\r
213          */\r
214         private GrabInfo getGrabInfo(IElement e, ICanvasContext ctx, int pointerId)\r
215         {\r
216                 DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
217                 Key key = new MouseSpecificKeyOf(pointerId, GrabInfo.class);            \r
218                 return dp.getElementHint(e, key);\r
219         }\r
220         \r
221         /**\r
222          * Get all pointer grabs\r
223          * @return\r
224          */\r
225         protected Map<Integer, GrabInfo> getGrabs(IElement e, ICanvasContext ctx)\r
226         {\r
227                 DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
228                 Map<Key, Object> map = dp.getElementHints(e);\r
229                 if (map==null) return null;\r
230                 Map<Integer, GrabInfo> result = new HashMap<Integer, GrabInfo>();\r
231                 for (Entry<Key, Object> entry : map.entrySet())\r
232                 {\r
233                         if (!(entry.getValue() instanceof GrabInfo)) continue;\r
234                         GrabInfo gi = (GrabInfo) entry.getValue();\r
235                         result.put(gi.pointerId, gi);\r
236                 }\r
237                 return result;\r
238         }       \r
239         \r
240         protected int getGrabCount(IElement e, ICanvasContext ctx)\r
241         {\r
242                 DiagramParticipant dp = ctx.getSingleItem(DiagramParticipant.class);\r
243                 Map<Key, Object> map = dp.getElementHints(e);\r
244                 if (map==null) return 0;\r
245                 int result = 0;\r
246                 for (Entry<Key, Object> entry : map.entrySet())\r
247                 {\r
248                         if (!(entry.getValue() instanceof GrabInfo)) continue;\r
249                         result ++;\r
250                 }\r
251                 return result;\r
252         }\r
253         \r
254         /**\r
255          * Release grab of a pointer\r
256          * @param e\r
257          * @param ctx\r
258          * @param pointerId\r
259          */\r
260         protected void releaseGrab(IElement e, ICanvasContext ctx, int pointerId)\r
261         {\r
262                 GrabInfo gi = getGrabInfo(e, ctx, pointerId);\r
263                 if (gi==null) return;\r
264                 gi.hnd.release();\r
265                 removeGrabInfo(e, ctx, pointerId);\r
266         }\r
267         \r
268         /**\r
269          * Grab a pointer\r
270          * @param e\r
271          * @param ctx\r
272          * @param pointerId\r
273          * @param grabPointControl\r
274          * @return\r
275          */\r
276         private GrabInfo grabMouse(IElement e, ICanvasContext ctx, int pointerId, Point2D grabPointControl)\r
277         {\r
278                 // Release previous capture, if exists\r
279                 releaseGrab(e, ctx, pointerId);         \r
280                 \r
281                 ElementInteractor ei = ctx.getSingleItem(ElementInteractor.class);\r
282                 IMouseCaptureHandle hnd = ei.captureMouse(e, pointerId);\r
283                 if (hnd == null) return null;\r
284 \r
285                 Point2D grabPointCanvas = ElementUtils.controlToCanvasCoordinate(ctx, grabPointControl, new Point2D.Double());\r
286                 Point2D grabPointElement = ElementUtils.controlToElementCoordinate(e, ctx, grabPointControl, new Point2D.Double());\r
287                 \r
288                 GrabInfo gi = new GrabInfo();\r
289                 gi.e = e;\r
290                 gi.hnd = hnd;\r
291                 gi.pointerId = pointerId;\r
292                 gi.grabPosControl.setLocation(grabPointControl);\r
293                 gi.grabPosCanvas.setLocation(grabPointCanvas);\r
294                 gi.grabPosElement.setLocation(grabPointElement);\r
295                 \r
296                 gi.dragPosControl.setLocation(grabPointControl);\r
297                 gi.dragPosCanvas.setLocation(grabPointCanvas);\r
298                 gi.dragPosElement.setLocation(grabPointElement);\r
299                                 \r
300                 gi.prevPosControl.setLocation(grabPointControl);\r
301                 gi.prevPosCanvas.setLocation(grabPointCanvas);\r
302                 gi.prevPosElement.setLocation(grabPointElement);\r
303                 \r
304                 setGrabInfo(e, ctx, pointerId, gi);\r
305                 \r
306                 return gi;\r
307         }       \r
308 \r
309 }\r