]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/G2DNode.java
Merge commit 'bd5bc6e45f700e755b61bd112631796631330ecb'
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / G2DNode.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.scenegraph.g2d;\r
13 \r
14 import java.awt.Component;\r
15 import java.awt.Cursor;\r
16 import java.awt.Shape;\r
17 import java.awt.geom.AffineTransform;\r
18 import java.awt.geom.NoninvertibleTransformException;\r
19 import java.awt.geom.Point2D;\r
20 import java.awt.geom.Rectangle2D;\r
21 \r
22 import org.simantics.scenegraph.INode;\r
23 import org.simantics.scenegraph.Node;\r
24 import org.simantics.scenegraph.ParentNode;\r
25 import org.simantics.scenegraph.g2d.events.Event;\r
26 import org.simantics.scenegraph.g2d.events.EventTypes;\r
27 import org.simantics.scenegraph.g2d.events.FocusEvent;\r
28 import org.simantics.scenegraph.g2d.events.IEventHandler;\r
29 import org.simantics.scenegraph.g2d.events.KeyEvent;\r
30 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;\r
31 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyReleasedEvent;\r
32 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;\r
33 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;\r
34 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent;\r
35 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent;\r
36 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
37 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent;\r
38 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;\r
39 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
40 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent;\r
41 import org.simantics.scenegraph.g2d.events.NodeEventHandler;\r
42 import org.simantics.scenegraph.g2d.events.TimeEvent;\r
43 import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
44 import org.simantics.scenegraph.utils.GeometryUtils;\r
45 import org.simantics.scenegraph.utils.NodeUtil;\r
46 \r
47 public abstract class G2DNode extends Node implements IG2DNode {\r
48 \r
49     private static final long serialVersionUID = 8283264115992894707L;\r
50 \r
51     protected int z = 0;\r
52     protected AffineTransform transform = IdentityAffineTransform.INSTANCE;\r
53 \r
54     @SyncField("z")\r
55     public void setZIndex(int z) {\r
56         if (z != this.z) {\r
57             G2DParentNode parent = (G2DParentNode) getParent();\r
58             if (parent != null)\r
59                 parent.invalidateChildOrder();\r
60             this.z = z;\r
61         }\r
62     }\r
63 \r
64     public int getZIndex() {\r
65         return z;\r
66     }\r
67     \r
68     public boolean validate() {\r
69         return true;\r
70     }\r
71     \r
72     @Override\r
73     public void cleanup() {\r
74         retractMapping();\r
75         repaint();\r
76     }\r
77 \r
78     public void repaint() {\r
79         INode parent = getParent();\r
80         while(parent != null && !(parent instanceof G2DSceneGraph))\r
81             parent = parent.getParent();\r
82         if(parent == null || ((G2DSceneGraph)parent).getRootPane() == null) return;\r
83         ((G2DSceneGraph)parent).getRootPane().repaint();\r
84     }\r
85 \r
86 \r
87     // Bounds and transformation\r
88 \r
89     public AffineTransform getTransform() {\r
90         return transform;\r
91     }\r
92 \r
93     @PropertySetter("Transform")\r
94     @SyncField("transform")\r
95     public void setTransform(AffineTransform transform) {\r
96         assert(transform != null);\r
97         if (transform.isIdentity())\r
98             this.transform = IdentityAffineTransform.INSTANCE;\r
99         else\r
100             this.transform = transform;\r
101     }\r
102 \r
103     /**\r
104      * Return bounds transformed with local transformation\r
105      * \r
106      * @return transformed bounds\r
107      */\r
108     public Rectangle2D getBounds() {\r
109         Rectangle2D local = getBoundsInLocal();\r
110         if (local == null)\r
111             return null;\r
112         // TODO: potential spot for CPU/memory allocation optimization\r
113         // by using more specialized implementations\r
114         return transform.createTransformedShape(local).getBounds2D();\r
115     }\r
116 \r
117     /**\r
118      * Return bounds in local coordinates\r
119      * \r
120      * @return bounds\r
121      */\r
122     abstract public Rectangle2D getBoundsInLocal();\r
123     \r
124     public Rectangle2D getBoundsInLocal(boolean ignoreNulls) {\r
125         return getBoundsInLocal();\r
126     }\r
127 \r
128     // Helper methods for bounds checking\r
129 \r
130     public boolean contains(Point2D point) {\r
131         Rectangle2D bounds = getBounds();\r
132         if(bounds == null) return false;\r
133         return bounds.contains(point);\r
134     }\r
135 \r
136     public boolean containsLocal(Point2D localPoint) {\r
137         Rectangle2D bounds = getBoundsInLocal();\r
138         if(bounds == null) return false;\r
139         return bounds.contains(localPoint);\r
140     }\r
141 \r
142     public boolean intersects(Rectangle2D b) {\r
143         if (b == null)\r
144             return true;\r
145         Rectangle2D a = getBounds();\r
146         if (a == null)\r
147             return true;\r
148         /*\r
149          * Compared to Rectangle2D.intersects, this\r
150          * intersects closed (not open) shapes.\r
151          */\r
152         double ax = a.getX();\r
153         double ay = a.getY();\r
154         double aw = a.getWidth();\r
155         double ah = a.getHeight();\r
156         double bx = b.getX();\r
157         double by = b.getY();\r
158         double bw = b.getWidth();\r
159         double bh = b.getHeight();\r
160         return (ax + aw >= bx &&\r
161                 ay + ah >= by &&\r
162                 ax <= bx + bw &&\r
163                 ay <= by + bh);\r
164     }\r
165 \r
166     public Point2D localToParent(Point2D point) {\r
167         return transform.transform(point, null);\r
168     }\r
169 \r
170     public Rectangle2D localToParent(Rectangle2D rect) {\r
171         return transform.createTransformedShape(rect).getBounds2D();\r
172     }\r
173 \r
174     public Point2D parentToLocal(Point2D point) {\r
175         AffineTransform inverse = null;\r
176         try {\r
177             inverse = transform.createInverse();\r
178             return inverse.transform(point, null);\r
179         } catch (NoninvertibleTransformException e) {\r
180             e.printStackTrace(); // FIXME\r
181         }\r
182         return point;\r
183     }\r
184 \r
185     public Point2D parentToLocal(Point2D src, Point2D dst) {\r
186         AffineTransform inverse = null;\r
187         try {\r
188             inverse = transform.createInverse();\r
189             return inverse.transform(src, dst);\r
190         } catch (NoninvertibleTransformException e) {\r
191             e.printStackTrace(); // FIXME\r
192         }\r
193         return src;\r
194     }\r
195 \r
196     public Rectangle2D parentToLocal(Rectangle2D rect) {\r
197         AffineTransform inverse = null;\r
198         try {\r
199             inverse = transform.createInverse();\r
200             return inverse.createTransformedShape(rect).getBounds2D();\r
201         } catch (NoninvertibleTransformException e) {\r
202             e.printStackTrace(); // FIXME\r
203         }\r
204         return rect;\r
205     }\r
206 \r
207     public Point2D localToControl(Point2D point) {\r
208         IG2DNode node = this;\r
209         while(node != null) {\r
210             point = node.getTransform().transform(point, null);\r
211             node = (G2DParentNode)node.getParent(); // FIXME: it should be G2DParentNode but you can never be sure\r
212         }\r
213         return point;\r
214     }\r
215 \r
216     public Rectangle2D localToControl(Rectangle2D rect) {\r
217         Shape shape = rect;\r
218         IG2DNode node = this;\r
219         while(node != null) {\r
220             shape = node.getTransform().createTransformedShape(shape);\r
221             node = (G2DParentNode)node.getParent(); // FIXME: it should be G2DParentNode but you can never be sure\r
222         }\r
223 \r
224         return shape.getBounds2D();\r
225     }\r
226 \r
227     public Point2D controlToLocal(Point2D point) {\r
228         AffineTransform at = NodeUtil.getGlobalToLocalTransform(this, null);\r
229         if (at == null)\r
230             return point;\r
231         return at.transform(point, null);\r
232     }\r
233 \r
234     public Rectangle2D controlToLocal(Rectangle2D rect) {\r
235         AffineTransform at = NodeUtil.getGlobalToLocalTransform(this, null);\r
236         if (at == null)\r
237             return rect;\r
238         return GeometryUtils.transformRectangle(at, rect);\r
239     }\r
240 \r
241     @Override\r
242     public String toString() {\r
243         return super.toString() + " [z=" + z + ",transform=" + transform + "]";\r
244     }\r
245 \r
246     /**\r
247      * @see org.simantics.scenegraph.g2d.IG2DNode#getRootNode()\r
248      */\r
249     public G2DSceneGraph getRootNode2D() {\r
250         ParentNode<?> root = getRootNode();\r
251         return (G2DSceneGraph) root;\r
252     }\r
253 \r
254     @Override\r
255     public boolean hasFocus() {\r
256         return getFocusNode() == this;\r
257     }\r
258 \r
259     @Override\r
260     public IG2DNode getFocusNode() {\r
261         return getRootNode2D().getFocusNode();\r
262     }\r
263 \r
264     @Override\r
265     public void setFocusNode(IG2DNode node) {\r
266         getRootNode2D().setFocusNode(node);\r
267     }\r
268 \r
269     protected NodeEventHandler getEventHandler() {\r
270         return NodeUtil.getNodeEventHandler(this);\r
271     }\r
272 \r
273     protected void addEventHandler(IEventHandler handler) {\r
274         getEventHandler().add(handler);\r
275     }\r
276 \r
277     protected void removeEventHandler(IEventHandler handler) {\r
278         getEventHandler().remove(handler);\r
279     }\r
280 \r
281     @Override\r
282     public int getEventMask() {\r
283         return 0;\r
284     }\r
285 \r
286     @Override\r
287     public boolean handleEvent(Event e) {\r
288         int eventType = EventTypes.toType(e);\r
289         switch (eventType) {\r
290             case EventTypes.Command:\r
291                 return handleCommand((CommandEvent) e);\r
292 \r
293             case EventTypes.FocusGained:\r
294             case EventTypes.FocusLost:\r
295                 return handleFocusEvent((FocusEvent) e);\r
296 \r
297             case EventTypes.KeyPressed:\r
298                 return keyPressed((KeyPressedEvent) e);\r
299             case EventTypes.KeyReleased:\r
300                 return keyReleased((KeyReleasedEvent) e);\r
301 \r
302             case EventTypes.MouseButtonPressed:\r
303                 return mouseButtonPressed((MouseButtonPressedEvent) e);\r
304             case EventTypes.MouseButtonReleased:\r
305                 return mouseButtonReleased((MouseButtonReleasedEvent) e);\r
306             case EventTypes.MouseClick:\r
307                 return mouseClicked((MouseClickEvent) e);\r
308             case EventTypes.MouseDoubleClick:\r
309                 return mouseDoubleClicked((MouseDoubleClickedEvent) e);\r
310             case EventTypes.MouseMoved:\r
311                 return mouseMoved((MouseMovedEvent) e);\r
312             case EventTypes.MouseDragBegin:\r
313                 return mouseDragged((MouseDragBegin) e);\r
314             case EventTypes.MouseEnter:\r
315                 return mouseEntered((MouseEnterEvent) e);\r
316             case EventTypes.MouseExit:\r
317                 return mouseExited((MouseExitEvent) e);\r
318             case EventTypes.MouseWheel:\r
319                 return mouseWheelMoved((MouseWheelMovedEvent) e);\r
320 \r
321             case EventTypes.Time:\r
322                 return handleTimeEvent((TimeEvent) e);\r
323         }\r
324         return false;\r
325     }\r
326 \r
327     protected boolean keyReleased(KeyReleasedEvent e) {\r
328         return false;\r
329     }\r
330 \r
331     protected boolean keyPressed(KeyPressedEvent e) {\r
332         return false;\r
333     }\r
334 \r
335     protected boolean handleCommand(CommandEvent e) {\r
336         return false;\r
337     }\r
338 \r
339     protected boolean handleFocusEvent(FocusEvent e) {\r
340         return false;\r
341     }\r
342 \r
343     protected boolean handleKeyEvent(KeyEvent e) {\r
344         return false;\r
345     }\r
346 \r
347     protected boolean mouseButtonPressed(MouseButtonPressedEvent e) {\r
348         return false;\r
349     }\r
350 \r
351     protected boolean mouseButtonReleased(MouseButtonReleasedEvent e) {\r
352         return false;\r
353     }\r
354 \r
355     protected boolean mouseClicked(MouseClickEvent e) {\r
356         return false;\r
357     }\r
358 \r
359     protected boolean mouseDoubleClicked(MouseDoubleClickedEvent e) {\r
360         return false;\r
361     }\r
362 \r
363     protected boolean mouseMoved(MouseMovedEvent e) {\r
364         return false;\r
365     }\r
366 \r
367     protected boolean mouseDragged(MouseDragBegin e) {\r
368         return false;\r
369     }\r
370 \r
371     protected boolean mouseEntered(MouseEnterEvent e) {\r
372         return false;\r
373     }\r
374 \r
375     protected boolean mouseExited(MouseExitEvent e) {\r
376         return false;\r
377     }\r
378 \r
379     protected boolean mouseWheelMoved(MouseWheelMovedEvent e) {\r
380         return false;\r
381     }\r
382 \r
383     protected boolean handleTimeEvent(TimeEvent e) {\r
384         return false;\r
385     }\r
386 \r
387     protected void setCursor(int cursorType) {\r
388         Component rootPane = NodeUtil.findRootPane(this);\r
389         if (rootPane != null)\r
390             rootPane.setCursor(Cursor.getPredefinedCursor(cursorType));\r
391     }\r
392 \r
393     protected void setCursor(Cursor cursor) {\r
394         Component rootPane = NodeUtil.findRootPane(this);\r
395         if (rootPane != null)\r
396             rootPane.setCursor(cursor);\r
397     }\r
398 \r
399 }\r