]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/G2DNode.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / G2DNode.java
diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/G2DNode.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/G2DNode.java
new file mode 100644 (file)
index 0000000..a558aa3
--- /dev/null
@@ -0,0 +1,399 @@
+/*******************************************************************************\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.scenegraph.g2d;\r
+\r
+import java.awt.Component;\r
+import java.awt.Cursor;\r
+import java.awt.Shape;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.NoninvertibleTransformException;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.simantics.scenegraph.INode;\r
+import org.simantics.scenegraph.Node;\r
+import org.simantics.scenegraph.ParentNode;\r
+import org.simantics.scenegraph.g2d.events.Event;\r
+import org.simantics.scenegraph.g2d.events.EventTypes;\r
+import org.simantics.scenegraph.g2d.events.FocusEvent;\r
+import org.simantics.scenegraph.g2d.events.IEventHandler;\r
+import org.simantics.scenegraph.g2d.events.KeyEvent;\r
+import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;\r
+import org.simantics.scenegraph.g2d.events.KeyEvent.KeyReleasedEvent;\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.MouseDoubleClickedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseEnterEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseExitEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;\r
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseWheelMovedEvent;\r
+import org.simantics.scenegraph.g2d.events.NodeEventHandler;\r
+import org.simantics.scenegraph.g2d.events.TimeEvent;\r
+import org.simantics.scenegraph.g2d.events.command.CommandEvent;\r
+import org.simantics.scenegraph.utils.GeometryUtils;\r
+import org.simantics.scenegraph.utils.NodeUtil;\r
+\r
+public abstract class G2DNode extends Node implements IG2DNode {\r
+\r
+    private static final long serialVersionUID = 8283264115992894707L;\r
+\r
+    protected int z = 0;\r
+    protected AffineTransform transform = IdentityAffineTransform.INSTANCE;\r
+\r
+    @SyncField("z")\r
+    public void setZIndex(int z) {\r
+        if (z != this.z) {\r
+            G2DParentNode parent = (G2DParentNode) getParent();\r
+            if (parent != null)\r
+                parent.invalidateChildOrder();\r
+            this.z = z;\r
+        }\r
+    }\r
+\r
+    public int getZIndex() {\r
+        return z;\r
+    }\r
+    \r
+    public boolean validate() {\r
+       return true;\r
+    }\r
+    \r
+    @Override\r
+    public void cleanup() {\r
+        retractMapping();\r
+        repaint();\r
+    }\r
+\r
+    public void repaint() {\r
+       INode parent = getParent();\r
+        while(parent != null && !(parent instanceof G2DSceneGraph))\r
+            parent = parent.getParent();\r
+        if(parent == null || ((G2DSceneGraph)parent).getRootPane() == null) return;\r
+        ((G2DSceneGraph)parent).getRootPane().repaint();\r
+    }\r
+\r
+\r
+    // Bounds and transformation\r
+\r
+    public AffineTransform getTransform() {\r
+        return transform;\r
+    }\r
+\r
+    @PropertySetter("Transform")\r
+    @SyncField("transform")\r
+    public void setTransform(AffineTransform transform) {\r
+        assert(transform != null);\r
+        if (transform.isIdentity())\r
+            this.transform = IdentityAffineTransform.INSTANCE;\r
+        else\r
+            this.transform = transform;\r
+    }\r
+\r
+    /**\r
+     * Return bounds transformed with local transformation\r
+     * \r
+     * @return transformed bounds\r
+     */\r
+    public Rectangle2D getBounds() {\r
+        Rectangle2D local = getBoundsInLocal();\r
+        if (local == null)\r
+            return null;\r
+        // TODO: potential spot for CPU/memory allocation optimization\r
+        // by using more specialized implementations\r
+        return transform.createTransformedShape(local).getBounds2D();\r
+    }\r
+\r
+    /**\r
+     * Return bounds in local coordinates\r
+     * \r
+     * @return bounds\r
+     */\r
+    abstract public Rectangle2D getBoundsInLocal();\r
+    \r
+    public Rectangle2D getBoundsInLocal(boolean ignoreNulls) {\r
+       return getBoundsInLocal();\r
+    }\r
+\r
+    // Helper methods for bounds checking\r
+\r
+    public boolean contains(Point2D point) {\r
+        Rectangle2D bounds = getBounds();\r
+        if(bounds == null) return false;\r
+        return bounds.contains(point);\r
+    }\r
+\r
+    public boolean containsLocal(Point2D localPoint) {\r
+        Rectangle2D bounds = getBoundsInLocal();\r
+        if(bounds == null) return false;\r
+        return bounds.contains(localPoint);\r
+    }\r
+\r
+    public boolean intersects(Rectangle2D b) {\r
+        if (b == null)\r
+            return true;\r
+        Rectangle2D a = getBounds();\r
+        if (a == null)\r
+            return true;\r
+        /*\r
+         * Compared to Rectangle2D.intersects, this\r
+         * intersects closed (not open) shapes.\r
+         */\r
+        double ax = a.getX();\r
+        double ay = a.getY();\r
+        double aw = a.getWidth();\r
+        double ah = a.getHeight();\r
+        double bx = b.getX();\r
+        double by = b.getY();\r
+        double bw = b.getWidth();\r
+        double bh = b.getHeight();\r
+        return (ax + aw >= bx &&\r
+                ay + ah >= by &&\r
+                ax <= bx + bw &&\r
+                ay <= by + bh);\r
+    }\r
+\r
+    public Point2D localToParent(Point2D point) {\r
+        return transform.transform(point, null);\r
+    }\r
+\r
+    public Rectangle2D localToParent(Rectangle2D rect) {\r
+        return transform.createTransformedShape(rect).getBounds2D();\r
+    }\r
+\r
+    public Point2D parentToLocal(Point2D point) {\r
+        AffineTransform inverse = null;\r
+        try {\r
+            inverse = transform.createInverse();\r
+            return inverse.transform(point, null);\r
+        } catch (NoninvertibleTransformException e) {\r
+            e.printStackTrace(); // FIXME\r
+        }\r
+        return point;\r
+    }\r
+\r
+    public Point2D parentToLocal(Point2D src, Point2D dst) {\r
+        AffineTransform inverse = null;\r
+        try {\r
+            inverse = transform.createInverse();\r
+            return inverse.transform(src, dst);\r
+        } catch (NoninvertibleTransformException e) {\r
+            e.printStackTrace(); // FIXME\r
+        }\r
+        return src;\r
+    }\r
+\r
+    public Rectangle2D parentToLocal(Rectangle2D rect) {\r
+        AffineTransform inverse = null;\r
+        try {\r
+            inverse = transform.createInverse();\r
+            return inverse.createTransformedShape(rect).getBounds2D();\r
+        } catch (NoninvertibleTransformException e) {\r
+            e.printStackTrace(); // FIXME\r
+        }\r
+        return rect;\r
+    }\r
+\r
+    public Point2D localToControl(Point2D point) {\r
+        IG2DNode node = this;\r
+        while(node != null) {\r
+            point = node.getTransform().transform(point, null);\r
+            node = (G2DParentNode)node.getParent(); // FIXME: it should be G2DParentNode but you can never be sure\r
+        }\r
+        return point;\r
+    }\r
+\r
+    public Rectangle2D localToControl(Rectangle2D rect) {\r
+        Shape shape = rect;\r
+        IG2DNode node = this;\r
+        while(node != null) {\r
+            shape = node.getTransform().createTransformedShape(shape);\r
+            node = (G2DParentNode)node.getParent(); // FIXME: it should be G2DParentNode but you can never be sure\r
+        }\r
+\r
+        return shape.getBounds2D();\r
+    }\r
+\r
+    public Point2D controlToLocal(Point2D point) {\r
+        AffineTransform at = NodeUtil.getGlobalToLocalTransform(this, null);\r
+        if (at == null)\r
+            return point;\r
+        return at.transform(point, null);\r
+    }\r
+\r
+    public Rectangle2D controlToLocal(Rectangle2D rect) {\r
+        AffineTransform at = NodeUtil.getGlobalToLocalTransform(this, null);\r
+        if (at == null)\r
+            return rect;\r
+        return GeometryUtils.transformRectangle(at, rect);\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        return super.toString() + " [z=" + z + ",transform=" + transform + "]";\r
+    }\r
+\r
+    /**\r
+     * @see org.simantics.scenegraph.g2d.IG2DNode#getRootNode()\r
+     */\r
+    public G2DSceneGraph getRootNode2D() {\r
+        ParentNode<?> root = getRootNode();\r
+        return (G2DSceneGraph) root;\r
+    }\r
+\r
+    @Override\r
+    public boolean hasFocus() {\r
+        return getFocusNode() == this;\r
+    }\r
+\r
+    @Override\r
+    public IG2DNode getFocusNode() {\r
+        return getRootNode2D().getFocusNode();\r
+    }\r
+\r
+    @Override\r
+    public void setFocusNode(IG2DNode node) {\r
+        getRootNode2D().setFocusNode(node);\r
+    }\r
+\r
+    protected NodeEventHandler getEventHandler() {\r
+        return NodeUtil.getNodeEventHandler(this);\r
+    }\r
+\r
+    protected void addEventHandler(IEventHandler handler) {\r
+        getEventHandler().add(handler);\r
+    }\r
+\r
+    protected void removeEventHandler(IEventHandler handler) {\r
+        getEventHandler().remove(handler);\r
+    }\r
+\r
+    @Override\r
+    public int getEventMask() {\r
+        return 0;\r
+    }\r
+\r
+    @Override\r
+    public boolean handleEvent(Event e) {\r
+        int eventType = EventTypes.toType(e);\r
+        switch (eventType) {\r
+            case EventTypes.Command:\r
+                return handleCommand((CommandEvent) e);\r
+\r
+            case EventTypes.FocusGained:\r
+            case EventTypes.FocusLost:\r
+                return handleFocusEvent((FocusEvent) e);\r
+\r
+            case EventTypes.KeyPressed:\r
+                return keyPressed((KeyPressedEvent) e);\r
+            case EventTypes.KeyReleased:\r
+                return keyReleased((KeyReleasedEvent) e);\r
+\r
+            case EventTypes.MouseButtonPressed:\r
+                return mouseButtonPressed((MouseButtonPressedEvent) e);\r
+            case EventTypes.MouseButtonReleased:\r
+                return mouseButtonReleased((MouseButtonReleasedEvent) e);\r
+            case EventTypes.MouseClick:\r
+                return mouseClicked((MouseClickEvent) e);\r
+            case EventTypes.MouseDoubleClick:\r
+                return mouseDoubleClicked((MouseDoubleClickedEvent) e);\r
+            case EventTypes.MouseMoved:\r
+                return mouseMoved((MouseMovedEvent) e);\r
+            case EventTypes.MouseDragBegin:\r
+                return mouseDragged((MouseDragBegin) e);\r
+            case EventTypes.MouseEnter:\r
+                return mouseEntered((MouseEnterEvent) e);\r
+            case EventTypes.MouseExit:\r
+                return mouseExited((MouseExitEvent) e);\r
+            case EventTypes.MouseWheel:\r
+                return mouseWheelMoved((MouseWheelMovedEvent) e);\r
+\r
+            case EventTypes.Time:\r
+                return handleTimeEvent((TimeEvent) e);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    protected boolean keyReleased(KeyReleasedEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean keyPressed(KeyPressedEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean handleCommand(CommandEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean handleFocusEvent(FocusEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean handleKeyEvent(KeyEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseButtonPressed(MouseButtonPressedEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseButtonReleased(MouseButtonReleasedEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseClicked(MouseClickEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseDoubleClicked(MouseDoubleClickedEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseMoved(MouseMovedEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseDragged(MouseDragBegin e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseEntered(MouseEnterEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseExited(MouseExitEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean mouseWheelMoved(MouseWheelMovedEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected boolean handleTimeEvent(TimeEvent e) {\r
+        return false;\r
+    }\r
+\r
+    protected void setCursor(int cursorType) {\r
+        Component rootPane = NodeUtil.findRootPane(this);\r
+        if (rootPane != null)\r
+            rootPane.setCursor(Cursor.getPredefinedCursor(cursorType));\r
+    }\r
+\r
+    protected void setCursor(Cursor cursor) {\r
+        Component rootPane = NodeUtil.findRootPane(this);\r
+        if (rootPane != null)\r
+            rootPane.setCursor(cursor);\r
+    }\r
+\r
+}\r