]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/TransformableSelectionNode.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / nodes / TransformableSelectionNode.java
index 8bf623c0b737b2ccbecc8985604e278b4146f698..3cb77242800a5395acdfb51a92ec8f819adfdf60 100644 (file)
-/*******************************************************************************\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.nodes;\r
-\r
-import java.awt.BasicStroke;\r
-import java.awt.Color;\r
-import java.awt.Cursor;\r
-import java.awt.Graphics2D;\r
-import java.awt.geom.AffineTransform;\r
-import java.awt.geom.Line2D;\r
-import java.awt.geom.Path2D;\r
-import java.awt.geom.Point2D;\r
-import java.awt.geom.Rectangle2D;\r
-\r
-import org.simantics.scenegraph.g2d.G2DNode;\r
-import org.simantics.scenegraph.g2d.G2DParentNode;\r
-import org.simantics.scenegraph.g2d.IG2DNode;\r
-import org.simantics.scenegraph.g2d.IdentityAffineTransform;\r
-import org.simantics.scenegraph.g2d.events.EventTypes;\r
-import org.simantics.scenegraph.g2d.events.MouseEvent;\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.MouseMovedEvent;\r
-import org.simantics.scenegraph.utils.GeometryUtils;\r
-import org.simantics.scenegraph.utils.NodeUtil;\r
-\r
-/**\r
- * @author J-P Laine\r
- * @author Tuukka Lehtonen\r
- */\r
-public class TransformableSelectionNode extends G2DNode {\r
-\r
-    public static interface TransformCallback {\r
-        public void moved(Point2D delta);\r
-        public void resized(Point2D delta);\r
-    }\r
-\r
-    private static final long serialVersionUID = -2879575230419873230L;\r
-\r
-    private static final int HEADER_HEIGHT = 10;\r
-\r
-    public transient static final BasicStroke SELECTION_STROKE = new BasicStroke(1.0f,\r
-            BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f,\r
-            new float[] { 5.0f, 5.0f }, 0.0f);\r
-\r
-    protected Rectangle2D                     bounds           = null;\r
-    protected Color                           color            = null;\r
-    protected Boolean                         resizeable       = Boolean.FALSE;\r
-\r
-    protected double                          minWidth         = 7;\r
-    protected double                          minHeight        = 7;\r
-\r
-    protected transient Point2D               dragDelta         = null;\r
-    protected transient Point2D               orig              = null;\r
-    protected transient Boolean               resize            = null;\r
-\r
-    protected transient Point2D               temp              = new Point2D.Double();\r
-    protected transient Path2D                path              = new Path2D.Double();\r
-    protected transient Rectangle2D           rect              = new Rectangle2D.Double();\r
-\r
-    protected transient TransformCallback     transformCallback = null;\r
-\r
-    @Override\r
-    public void init() {\r
-        super.init();\r
-        addEventHandler(this);\r
-    }\r
-\r
-    @Override\r
-    public void cleanup() {\r
-        removeEventHandler(this);\r
-        super.cleanup();\r
-    }\r
-\r
-    @SyncField({"transform", "bounds", "color", "resizeable", "minWidth", "minHeight"})\r
-    public void init(AffineTransform transform, Rectangle2D bounds, Color color, boolean resizeable, double minWidth, double minHeight) {\r
-//        System.out.println("init("+transform+", "+bounds+", "+color+", "+resizeable+")");\r
-        this.transform = transform;\r
-        this.bounds = bounds;\r
-        this.color = color;\r
-        this.resizeable = resizeable;\r
-        this.minWidth = minWidth;\r
-        this.minHeight = minHeight;\r
-    }\r
-\r
-    @SyncField({"transform", "bounds", "color", "resizeable"})\r
-    public void init(AffineTransform transform, Rectangle2D bounds, Color color, boolean resizeable) {\r
-//        System.out.println("init("+transform+", "+bounds+", "+color+", "+resizeable+")");\r
-        this.transform = transform;\r
-        this.bounds = bounds;\r
-        this.color = color;\r
-        this.resizeable = resizeable;\r
-    }\r
-\r
-    @SyncField({"transform", "bounds", "color"})\r
-    public void init(AffineTransform transform, Rectangle2D bounds, Color color) {\r
-//        System.out.println("init("+transform+", "+bounds+", "+color+")");\r
-        this.transform = transform;\r
-        this.bounds = bounds;\r
-        this.color = color;\r
-    }\r
-\r
-    @Override\r
-    public void render(Graphics2D g) {\r
-        if (bounds == null)\r
-            return;\r
-        AffineTransform ot = g.getTransform();\r
-\r
-        g.setColor(color);\r
-        g.transform(transform);\r
-\r
-        AffineTransform tx = g.getTransform();\r
-        //System.out.println("tx: " + tx);\r
-        double scale = GeometryUtils.getScale(tx);\r
-        //System.out.println("scale: " + scale);\r
-        double scaleRecip = 1.0 / scale;\r
-        //System.out.println("scale: " + scaleRecip);\r
-\r
-        BasicStroke scaledStroke = GeometryUtils.scaleStroke( SELECTION_STROKE, (float) scaleRecip);\r
-        g.setStroke(scaledStroke);\r
-\r
-        double padding = 0.0 * scaleRecip;\r
-        double paddingX = padding;\r
-        double paddingY = padding;\r
-\r
-        g.draw(new Rectangle2D.Double(bounds.getMinX() - paddingX, bounds.getMinY() - paddingY,\r
-                bounds.getWidth() + 2.0*paddingX, bounds.getHeight() + 2.0*paddingY));\r
-\r
-        double right = (bounds.getMinX() - paddingX + bounds.getWidth() + 2.0*paddingX);\r
-        double bottom = (bounds.getMinY() - paddingY + bounds.getHeight() + 2.0*paddingY);\r
-\r
-        if (resizeable) {\r
-            Path2D corner = new Path2D.Double();\r
-            corner.moveTo(right-8-paddingX, bottom);\r
-            corner.lineTo(right, bottom - 8 - paddingY);\r
-            corner.lineTo(right, bottom);\r
-            corner.closePath();\r
-            g.setColor(new Color(20, 20, 20, 120));\r
-            g.fill(corner);\r
-\r
-            g.setColor(color);\r
-            g.draw(new Line2D.Double(right-8-paddingX, bottom, right, bottom - 8 - paddingY));\r
-        }\r
-\r
-        Rectangle2D header = new Rectangle2D.Double(bounds.getMinX() - paddingX, bounds.getMinY() - paddingY, bounds.getWidth() + 2.0*paddingX, HEADER_HEIGHT);\r
-        g.setColor(new Color(20, 20, 20, 120));\r
-        g.fill(header);\r
-\r
-        g.setColor(color);\r
-        g.draw(new Line2D.Double(bounds.getMinX(), bounds.getMinY()+HEADER_HEIGHT, right, bounds.getMinY()+HEADER_HEIGHT));\r
-\r
-        g.setTransform(ot);\r
-    }\r
-\r
-    @Override\r
-    public Rectangle2D getBoundsInLocal() {\r
-        return bounds;\r
-    }\r
-\r
-    public void setTransformCallback(TransformCallback transformCallback) {\r
-        this.transformCallback = transformCallback;\r
-    }\r
-\r
-    @ServerSide\r
-    protected void resized(Point2D size) {\r
-        if (transformCallback != null) {\r
-            transformCallback.resized(size);\r
-        }\r
-    }\r
-\r
-    @ServerSide\r
-    protected void moved(Point2D location) {\r
-        if (transformCallback != null) {\r
-            transformCallback.moved(location);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public boolean mouseMoved(MouseMovedEvent e) {\r
-        boolean consume = false;\r
-\r
-        Point2D scale = getScale(temp);\r
-        final double sx = scale.getX();\r
-        final double sy = scale.getY();\r
-\r
-        Point2D localPos = NodeUtil.worldToLocal(this, e.controlPosition, temp);\r
-        final double mx = localPos.getX();\r
-        final double my = localPos.getY();\r
-\r
-        AffineTransform i = AffineTransform.getTranslateInstance(-transform.getTranslateX()*sx, -transform.getTranslateY()*sy);\r
-        Point2D p = i.transform(new Point2D.Double(sx*mx, sy*my), null);\r
-\r
-        boolean dragging = (e.buttons & MouseEvent.LEFT_MASK) != 0;\r
-\r
-        if (dragging && dragDelta != null) {\r
-            double x = (p.getX() - dragDelta.getX())/sx;// /transform.getScaleX();\r
-            double y = (p.getY() - dragDelta.getY())/sy;// /transform.getScaleY();\r
-            if (Boolean.TRUE.equals(resize)) {\r
-\r
-                double width;\r
-                double pointX;\r
-                if (bounds.getWidth() + x < minWidth) {\r
-                    width = minWidth;\r
-                    pointX = dragDelta.getX();\r
-                } else {\r
-                    width = bounds.getWidth() + x;\r
-                    pointX = p.getX();\r
-                }\r
-\r
-                double height;\r
-                double pointY;\r
-                if (bounds.getHeight() + y < minHeight) {\r
-                    height = minHeight;\r
-                    pointY = dragDelta.getY();\r
-                } else {\r
-                    height = bounds.getHeight() + y;\r
-                    pointY = p.getY();\r
-                }\r
-\r
-//              System.out.println("bounds.getX()=" + bounds.getX() + " bounds.getY())=" + bounds.getY());\r
-//              System.out.println("width=" + width + " height=" + height);\r
-\r
-                bounds.setFrame(bounds.getX(), bounds.getY(), width, height);\r
-                dragDelta = new Point2D.Double(pointX, pointY); // TODO ..\r
-\r
-            } else if (Boolean.FALSE.equals(resize)) {\r
-                if (transform == IdentityAffineTransform.INSTANCE)\r
-                    transform = AffineTransform.getTranslateInstance(x, y);\r
-                else\r
-                    transform.translate(x, y);\r
-            }\r
-\r
-            //dragDelta = new Point2D.Double(me.getPoint().getX(), me.getPoint().getY());\r
-            repaint();\r
-        } else {\r
-            final double paddingX = 0.0;\r
-            final double paddingY = 0.0;\r
-\r
-            Path2D corner = createCorner(path, bounds, paddingX, paddingY, sx, sy);\r
-            Rectangle2D header = createRectangle(rect, bounds, paddingX, paddingY, sx, sy);\r
-\r
-            if (corner.contains(p)) {\r
-                setCursor(Cursor.HAND_CURSOR);\r
-                //consume = true;\r
-            } else if (header.contains(p)) {\r
-                setCursor(Cursor.HAND_CURSOR);\r
-                //consume = true;\r
-            } else {\r
-                setCursor(Cursor.DEFAULT_CURSOR);\r
-            }\r
-        }\r
-\r
-        return consume;\r
-    }\r
-\r
-    @Override\r
-    protected boolean mouseButtonPressed(MouseButtonPressedEvent e) {\r
-        boolean consume = false;\r
-\r
-        if (e.button == MouseEvent.LEFT_BUTTON && !e.hasAnyModifier(MouseEvent.ALL_MODIFIERS_MASK)) {\r
-            Point2D scale = getScale(temp);\r
-            final double sx = scale.getX();\r
-            final double sy = scale.getY();\r
-\r
-            Point2D localPos = NodeUtil.worldToLocal(this, e.controlPosition, temp);\r
-            final double mx = localPos.getX();\r
-            final double my = localPos.getY();\r
-\r
-            AffineTransform i = AffineTransform.getTranslateInstance(-transform.getTranslateX()*sx, -transform.getTranslateY()*sy);\r
-            Point2D p = i.transform(new Point2D.Double(sx*mx, sy*my), null);\r
-\r
-            final double paddingX = 0.0;\r
-            final double paddingY = 0.0;\r
-\r
-            Path2D corner = createCorner(path, bounds, paddingX, paddingY, sx, sy);\r
-            Rectangle2D header = createRectangle(rect, bounds, paddingX, paddingY, sx, sy);\r
-\r
-            if (corner.contains(p)) {// me.getPoint().getX() > right-5-paddingX && me.getPoint().getY() > bottom - 5 - paddingY) {\r
-                if (orig == null)\r
-                    orig = new Point2D.Double(bounds.getWidth(), bounds.getHeight());\r
-                resize = Boolean.TRUE;\r
-                setCursor(Cursor.SE_RESIZE_CURSOR);\r
-                consume = true;\r
-            } else if (header.contains(p)) {// me.getPoint().getY() < bounds.getMinY()+8) {\r
-                if (orig == null)\r
-                    orig = new Point2D.Double(transform.getTranslateX(), transform.getTranslateY());\r
-                resize = Boolean.FALSE;\r
-                setCursor(Cursor.MOVE_CURSOR);\r
-                consume = true;\r
-            } else {\r
-                resize = null;\r
-            }\r
-\r
-            dragDelta = new Point2D.Double(p.getX(), p.getY());\r
-\r
-            repaint();\r
-        }\r
-        return consume;\r
-    }\r
-\r
-    @Override\r
-    protected boolean mouseButtonReleased(MouseButtonReleasedEvent e) {\r
-        if (orig != null) {\r
-            setCursor(Cursor.DEFAULT_CURSOR);\r
-            if (resize) {\r
-                Point2D delta = new Point2D.Double(bounds.getWidth() - orig.getX(), bounds.getHeight() - orig.getY());\r
-                resized(delta);\r
-            } else {\r
-                Point2D delta = new Point2D.Double((transform.getTranslateX() - orig.getX()), (transform.getTranslateY() - orig.getY()));\r
-                moved(delta);\r
-            }\r
-            orig = null;\r
-            return true;\r
-        }\r
-        return false;\r
-    }\r
-\r
-    @Override\r
-    public int getEventMask() {\r
-        return EventTypes.MouseButtonPressedMask | EventTypes.MouseButtonReleasedMask | EventTypes.MouseMovedMask;\r
-    }\r
-\r
-    private Point2D getScale(Point2D result) {\r
-        double sx = 1.0, sy = 1.0;\r
-        IG2DNode node = (IG2DNode) this.getParent();\r
-        while (node != null) {\r
-            sx *= node.getTransform().getScaleX();\r
-            sy *= node.getTransform().getScaleY();\r
-            // FIXME: it should be G2DParentNode but you can never be sure\r
-            node = (G2DParentNode) node.getParent();\r
-        }\r
-        result.setLocation(sx, sy);\r
-        return result;\r
-    }\r
-\r
-    private static Rectangle2D createRectangle(Rectangle2D result, Rectangle2D bounds,\r
-            double paddingX, double paddingY, double sx, double sy) {\r
-        result.setFrame(\r
-                (bounds.getMinX() - paddingX)*sx,\r
-                (bounds.getMinY() - paddingY)*sy,\r
-                (bounds.getWidth() + 2.0 * paddingX) * sx,\r
-                HEADER_HEIGHT*sy);\r
-        return result;\r
-    }\r
-\r
-    private static Path2D createCorner(Path2D result, Rectangle2D bounds,\r
-            double paddingX, double paddingY, double sx, double sy) {\r
-        final double right = (bounds.getMinX() - paddingX + bounds.getWidth() + 2.0 * paddingX);\r
-        final double bottom = (bounds.getMinY() - paddingY + bounds.getHeight() + 2.0 * paddingY);\r
-        result.reset();\r
-        result.moveTo((right - 8 - paddingX) * sx, bottom * sy);\r
-        result.lineTo(right * sx, (bottom - 8 - paddingY) * sy);\r
-        result.lineTo(right * sx, bottom * sy);\r
-        result.closePath();\r
-        return result;\r
-    }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.scenegraph.g2d.nodes;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import org.simantics.scenegraph.g2d.G2DNode;
+import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.scenegraph.g2d.IG2DNode;
+import org.simantics.scenegraph.g2d.IdentityAffineTransform;
+import org.simantics.scenegraph.g2d.events.EventTypes;
+import org.simantics.scenegraph.g2d.events.MouseEvent;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonPressedEvent;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent;
+import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;
+import org.simantics.scenegraph.utils.GeometryUtils;
+import org.simantics.scenegraph.utils.NodeUtil;
+
+/**
+ * @author J-P Laine
+ * @author Tuukka Lehtonen
+ */
+public class TransformableSelectionNode extends G2DNode {
+
+    public static interface TransformCallback {
+        public void moved(Point2D delta);
+        public void resized(Point2D delta);
+    }
+
+    private static final long serialVersionUID = -2879575230419873230L;
+
+    private static final int HEADER_HEIGHT = 10;
+
+    public transient static final BasicStroke SELECTION_STROKE = new BasicStroke(1.0f,
+            BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f,
+            new float[] { 5.0f, 5.0f }, 0.0f);
+
+    protected Rectangle2D                     bounds           = null;
+    protected Color                           color            = null;
+    protected Boolean                         resizeable       = Boolean.FALSE;
+
+    protected double                          minWidth         = 7;
+    protected double                          minHeight        = 7;
+
+    protected transient Point2D               dragDelta         = null;
+    protected transient Point2D               orig              = null;
+    protected transient Boolean               resize            = null;
+
+    protected transient Point2D               temp              = new Point2D.Double();
+    protected transient Path2D                path              = new Path2D.Double();
+    protected transient Rectangle2D           rect              = new Rectangle2D.Double();
+
+    protected transient TransformCallback     transformCallback = null;
+
+    @Override
+    public void init() {
+        super.init();
+        addEventHandler(this);
+    }
+
+    @Override
+    public void cleanup() {
+        removeEventHandler(this);
+        super.cleanup();
+    }
+
+    @SyncField({"transform", "bounds", "color", "resizeable", "minWidth", "minHeight"})
+    public void init(AffineTransform transform, Rectangle2D bounds, Color color, boolean resizeable, double minWidth, double minHeight) {
+//        System.out.println("init("+transform+", "+bounds+", "+color+", "+resizeable+")");
+        this.transform = transform;
+        this.bounds = bounds;
+        this.color = color;
+        this.resizeable = resizeable;
+        this.minWidth = minWidth;
+        this.minHeight = minHeight;
+    }
+
+    @SyncField({"transform", "bounds", "color", "resizeable"})
+    public void init(AffineTransform transform, Rectangle2D bounds, Color color, boolean resizeable) {
+//        System.out.println("init("+transform+", "+bounds+", "+color+", "+resizeable+")");
+        this.transform = transform;
+        this.bounds = bounds;
+        this.color = color;
+        this.resizeable = resizeable;
+    }
+
+    @SyncField({"transform", "bounds", "color"})
+    public void init(AffineTransform transform, Rectangle2D bounds, Color color) {
+//        System.out.println("init("+transform+", "+bounds+", "+color+")");
+        this.transform = transform;
+        this.bounds = bounds;
+        this.color = color;
+    }
+
+    @Override
+    public void render(Graphics2D g) {
+        if (bounds == null)
+            return;
+        AffineTransform ot = g.getTransform();
+
+        g.setColor(color);
+        g.transform(transform);
+
+        AffineTransform tx = g.getTransform();
+        //System.out.println("tx: " + tx);
+        double scale = GeometryUtils.getScale(tx);
+        //System.out.println("scale: " + scale);
+        double scaleRecip = 1.0 / scale;
+        //System.out.println("scale: " + scaleRecip);
+
+        BasicStroke scaledStroke = GeometryUtils.scaleStroke( SELECTION_STROKE, (float) scaleRecip);
+        g.setStroke(scaledStroke);
+
+        double padding = 0.0 * scaleRecip;
+        double paddingX = padding;
+        double paddingY = padding;
+
+        g.draw(new Rectangle2D.Double(bounds.getMinX() - paddingX, bounds.getMinY() - paddingY,
+                bounds.getWidth() + 2.0*paddingX, bounds.getHeight() + 2.0*paddingY));
+
+        double right = (bounds.getMinX() - paddingX + bounds.getWidth() + 2.0*paddingX);
+        double bottom = (bounds.getMinY() - paddingY + bounds.getHeight() + 2.0*paddingY);
+
+        if (resizeable) {
+            Path2D corner = new Path2D.Double();
+            corner.moveTo(right-8-paddingX, bottom);
+            corner.lineTo(right, bottom - 8 - paddingY);
+            corner.lineTo(right, bottom);
+            corner.closePath();
+            g.setColor(new Color(20, 20, 20, 120));
+            g.fill(corner);
+
+            g.setColor(color);
+            g.draw(new Line2D.Double(right-8-paddingX, bottom, right, bottom - 8 - paddingY));
+        }
+
+        Rectangle2D header = new Rectangle2D.Double(bounds.getMinX() - paddingX, bounds.getMinY() - paddingY, bounds.getWidth() + 2.0*paddingX, HEADER_HEIGHT);
+        g.setColor(new Color(20, 20, 20, 120));
+        g.fill(header);
+
+        g.setColor(color);
+        g.draw(new Line2D.Double(bounds.getMinX(), bounds.getMinY()+HEADER_HEIGHT, right, bounds.getMinY()+HEADER_HEIGHT));
+
+        g.setTransform(ot);
+    }
+
+    @Override
+    public Rectangle2D getBoundsInLocal() {
+        return bounds;
+    }
+
+    public void setTransformCallback(TransformCallback transformCallback) {
+        this.transformCallback = transformCallback;
+    }
+
+    @ServerSide
+    protected void resized(Point2D size) {
+        if (transformCallback != null) {
+            transformCallback.resized(size);
+        }
+    }
+
+    @ServerSide
+    protected void moved(Point2D location) {
+        if (transformCallback != null) {
+            transformCallback.moved(location);
+        }
+    }
+
+    @Override
+    public boolean mouseMoved(MouseMovedEvent e) {
+        boolean consume = false;
+
+        Point2D scale = getScale(temp);
+        final double sx = scale.getX();
+        final double sy = scale.getY();
+
+        Point2D localPos = NodeUtil.worldToLocal(this, e.controlPosition, temp);
+        final double mx = localPos.getX();
+        final double my = localPos.getY();
+
+        AffineTransform i = AffineTransform.getTranslateInstance(-transform.getTranslateX()*sx, -transform.getTranslateY()*sy);
+        Point2D p = i.transform(new Point2D.Double(sx*mx, sy*my), null);
+
+        boolean dragging = (e.buttons & MouseEvent.LEFT_MASK) != 0;
+
+        if (dragging && dragDelta != null) {
+            double x = (p.getX() - dragDelta.getX())/sx;// /transform.getScaleX();
+            double y = (p.getY() - dragDelta.getY())/sy;// /transform.getScaleY();
+            if (Boolean.TRUE.equals(resize)) {
+
+                double width;
+                double pointX;
+                if (bounds.getWidth() + x < minWidth) {
+                    width = minWidth;
+                    pointX = dragDelta.getX();
+                } else {
+                    width = bounds.getWidth() + x;
+                    pointX = p.getX();
+                }
+
+                double height;
+                double pointY;
+                if (bounds.getHeight() + y < minHeight) {
+                    height = minHeight;
+                    pointY = dragDelta.getY();
+                } else {
+                    height = bounds.getHeight() + y;
+                    pointY = p.getY();
+                }
+
+//              System.out.println("bounds.getX()=" + bounds.getX() + " bounds.getY())=" + bounds.getY());
+//              System.out.println("width=" + width + " height=" + height);
+
+                bounds.setFrame(bounds.getX(), bounds.getY(), width, height);
+                dragDelta = new Point2D.Double(pointX, pointY); // TODO ..
+
+            } else if (Boolean.FALSE.equals(resize)) {
+                if (transform == IdentityAffineTransform.INSTANCE)
+                    transform = AffineTransform.getTranslateInstance(x, y);
+                else
+                    transform.translate(x, y);
+            }
+
+            //dragDelta = new Point2D.Double(me.getPoint().getX(), me.getPoint().getY());
+            repaint();
+        } else {
+            final double paddingX = 0.0;
+            final double paddingY = 0.0;
+
+            Path2D corner = createCorner(path, bounds, paddingX, paddingY, sx, sy);
+            Rectangle2D header = createRectangle(rect, bounds, paddingX, paddingY, sx, sy);
+
+            if (corner.contains(p)) {
+                setCursor(Cursor.HAND_CURSOR);
+                //consume = true;
+            } else if (header.contains(p)) {
+                setCursor(Cursor.HAND_CURSOR);
+                //consume = true;
+            } else {
+                setCursor(Cursor.DEFAULT_CURSOR);
+            }
+        }
+
+        return consume;
+    }
+
+    @Override
+    protected boolean mouseButtonPressed(MouseButtonPressedEvent e) {
+        boolean consume = false;
+
+        if (e.button == MouseEvent.LEFT_BUTTON && !e.hasAnyModifier(MouseEvent.ALL_MODIFIERS_MASK)) {
+            Point2D scale = getScale(temp);
+            final double sx = scale.getX();
+            final double sy = scale.getY();
+
+            Point2D localPos = NodeUtil.worldToLocal(this, e.controlPosition, temp);
+            final double mx = localPos.getX();
+            final double my = localPos.getY();
+
+            AffineTransform i = AffineTransform.getTranslateInstance(-transform.getTranslateX()*sx, -transform.getTranslateY()*sy);
+            Point2D p = i.transform(new Point2D.Double(sx*mx, sy*my), null);
+
+            final double paddingX = 0.0;
+            final double paddingY = 0.0;
+
+            Path2D corner = createCorner(path, bounds, paddingX, paddingY, sx, sy);
+            Rectangle2D header = createRectangle(rect, bounds, paddingX, paddingY, sx, sy);
+
+            if (corner.contains(p)) {// me.getPoint().getX() > right-5-paddingX && me.getPoint().getY() > bottom - 5 - paddingY) {
+                if (orig == null)
+                    orig = new Point2D.Double(bounds.getWidth(), bounds.getHeight());
+                resize = Boolean.TRUE;
+                setCursor(Cursor.SE_RESIZE_CURSOR);
+                consume = true;
+            } else if (header.contains(p)) {// me.getPoint().getY() < bounds.getMinY()+8) {
+                if (orig == null)
+                    orig = new Point2D.Double(transform.getTranslateX(), transform.getTranslateY());
+                resize = Boolean.FALSE;
+                setCursor(Cursor.MOVE_CURSOR);
+                consume = true;
+            } else {
+                resize = null;
+            }
+
+            dragDelta = new Point2D.Double(p.getX(), p.getY());
+
+            repaint();
+        }
+        return consume;
+    }
+
+    @Override
+    protected boolean mouseButtonReleased(MouseButtonReleasedEvent e) {
+        if (orig != null) {
+            setCursor(Cursor.DEFAULT_CURSOR);
+            if (resize) {
+                Point2D delta = new Point2D.Double(bounds.getWidth() - orig.getX(), bounds.getHeight() - orig.getY());
+                resized(delta);
+            } else {
+                Point2D delta = new Point2D.Double((transform.getTranslateX() - orig.getX()), (transform.getTranslateY() - orig.getY()));
+                moved(delta);
+            }
+            orig = null;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int getEventMask() {
+        return EventTypes.MouseButtonPressedMask | EventTypes.MouseButtonReleasedMask | EventTypes.MouseMovedMask;
+    }
+
+    private Point2D getScale(Point2D result) {
+        double sx = 1.0, sy = 1.0;
+        IG2DNode node = (IG2DNode) this.getParent();
+        while (node != null) {
+            sx *= node.getTransform().getScaleX();
+            sy *= node.getTransform().getScaleY();
+            // FIXME: it should be G2DParentNode but you can never be sure
+            node = (G2DParentNode) node.getParent();
+        }
+        result.setLocation(sx, sy);
+        return result;
+    }
+
+    private static Rectangle2D createRectangle(Rectangle2D result, Rectangle2D bounds,
+            double paddingX, double paddingY, double sx, double sy) {
+        result.setFrame(
+                (bounds.getMinX() - paddingX)*sx,
+                (bounds.getMinY() - paddingY)*sy,
+                (bounds.getWidth() + 2.0 * paddingX) * sx,
+                HEADER_HEIGHT*sy);
+        return result;
+    }
+
+    private static Path2D createCorner(Path2D result, Rectangle2D bounds,
+            double paddingX, double paddingY, double sx, double sy) {
+        final double right = (bounds.getMinX() - paddingX + bounds.getWidth() + 2.0 * paddingX);
+        final double bottom = (bounds.getMinY() - paddingY + bounds.getHeight() + 2.0 * paddingY);
+        result.reset();
+        result.moveTo((right - 8 - paddingX) * sx, bottom * sy);
+        result.lineTo(right * sx, (bottom - 8 - paddingY) * sy);
+        result.lineTo(right * sx, bottom * sy);
+        result.closePath();
+        return result;
+    }
+
+}