G2DParentNode handles "undefined" child bounds separately 84/3584/1
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 20 Nov 2019 14:33:29 +0000 (16:33 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Wed, 20 Nov 2019 14:55:07 +0000 (14:55 +0000)
Previously nodes could only return null to say "I have no bounds".
Now it is possible to return GeometryUtils.undefinedBounds() to say
"ignore my bounds" to G2DParentNode.

Also allow customization of the node class used by ElementPainter to
mark selections under "element nodes" through a new configuration class
ElementPainterConfiguration.

This allows e.g. district to use its own node for this purpose to
optimize the scene graph and customize the bounds it returns.

gitlab #419

Change-Id: I210fd26be5d269847277616b9d5c52ef4f930dd7
(cherry picked from commit ad29e24f50e336add4c28df14312b3134ab93427)

bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementPainter.java
bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementPainterConfiguration.java [new file with mode: 0644]
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/G2DParentNode.java
bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/GeometryUtils.java

index 71b87c7141006cd5f114c7e779a047af93e785b9..7896e52a716a608b7ee307425f295156dc42cc32 100644 (file)
@@ -158,7 +158,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
     SingleElementNode diagramParent;
     RTreeNode elementParent;
 
-    boolean paintSelectionFrames;
+    ElementPainterConfiguration cfg;
 
     /**
      * Internally reused to avert constant reallocation.
@@ -174,7 +174,11 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
     }
 
     public ElementPainter(boolean paintSelectionFrames) {
-        this.paintSelectionFrames = paintSelectionFrames;
+        this(new ElementPainterConfiguration().paintSelectionFrames(paintSelectionFrames));
+    }
+
+    public ElementPainter(ElementPainterConfiguration cfg) {
+        this.cfg = cfg;
     }
 
     @Override
@@ -828,7 +832,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         Object task = BEGIN("EP.updateSelections");
 
         try {
-            if (!paintSelectionFrames)
+            if (!cfg.paintSelectionFrames)
                 return;
             if (selection == null)
                 return;
@@ -934,7 +938,7 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         Object task = BEGIN("EP.updateSelection");
 
         try {
-            if (!paintSelectionFrames)
+            if (!cfg.paintSelectionFrames)
                 return;
 
             G2DParentNode elementNode = (G2DParentNode) el.getHint(ElementHints.KEY_SG_NODE);
@@ -980,12 +984,14 @@ public class ElementPainter extends AbstractDiagramParticipant implements Compos
         Color color = getSelectionColor(selectionId);
         G2DParentNode selectionsNode = getSelectionsNode(selectionId);
 
+        Class<? extends G2DParentNode> selectionNodeClass = cfg.selectionNodeClass != null ? cfg.selectionNodeClass : G2DParentNode.class;
+
         for (IElement e : selection) {
             Node elementNode = e.getHint(ElementHints.KEY_SG_NODE);
 //            System.out.println("selectionNode: " + elementNode + " " + e);
             if (elementNode instanceof G2DParentNode) {
                 G2DParentNode en = (G2DParentNode) elementNode;
-                G2DParentNode selectionNode = en.getOrCreateNode(NodeUtil.SELECTION_NODE_NAME, G2DParentNode.class);
+                G2DParentNode selectionNode = en.getOrCreateNode(NodeUtil.SELECTION_NODE_NAME, selectionNodeClass);
                 selectionNode.setZIndex(SELECTION_PAINT_PRIORITY);
                 if (selectionNodes != null)
                     selectionNodes.add(selectionNode);
diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementPainterConfiguration.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/participant/ElementPainterConfiguration.java
new file mode 100644 (file)
index 0000000..304b4e6
--- /dev/null
@@ -0,0 +1,21 @@
+package org.simantics.g2d.diagram.participant;
+
+import org.simantics.scenegraph.g2d.G2DParentNode;
+
+public class ElementPainterConfiguration {
+
+       public boolean paintSelectionFrames = true;
+
+       public Class<? extends G2DParentNode> selectionNodeClass;
+
+       public ElementPainterConfiguration paintSelectionFrames(boolean paint) {
+               this.paintSelectionFrames = paint;
+               return this;
+       }
+
+       public ElementPainterConfiguration selectionNodeClass(Class<? extends G2DParentNode> clazz) {
+               this.selectionNodeClass = clazz;
+               return this;
+       }
+
+}
index de4631e770187c8db2f1a372776a8aea9175797d..af8c5630dc84c88c46c350b07c540ee9926e9ae6 100644 (file)
@@ -353,10 +353,12 @@ public class G2DParentNode extends ParentNode<IG2DNode> implements IG2DNode, Ini
             if(b == null && !ignoreNulls)
                 return null;
             if(b != null) {
-                if(bounds == null) {
-                    bounds = b.getFrame();
-                } else {
-                    bounds.add(b);
+                if(!GeometryUtils.isUndefinedRectangle(b)) {
+                    if(bounds == null) {
+                        bounds = b.getFrame();
+                    } else {
+                        bounds.add(b);
+                    }
                 }
             }
         }
index a3f4ec8bee57b770491b4a7da99a606928cf5fc7..cdda4f45c2de18fe4132f6a034c31bcd26dfe799 100644 (file)
@@ -507,5 +507,75 @@ public final class GeometryUtils {
         //System.out.println("FIT TRANSFORM: " + at);
         return at;
     }
-    
+
+    private static class UndefinedRectangle extends Rectangle2D {
+
+        @Override
+        public void setRect(double x, double y, double w, double h) {
+            throw new UnsupportedOperationException("UndefinedRectangle is immutable");
+        }
+
+        @Override
+        public int outcode(double x, double y) {
+            return OUT_LEFT | OUT_TOP | OUT_RIGHT | OUT_BOTTOM;
+        }
+
+        private Rectangle2D copy(Rectangle2D r) {
+            Rectangle2D dest;
+            if (r instanceof Float) {
+                dest = new Rectangle2D.Float();
+            } else {
+                dest = new Rectangle2D.Double();
+            }
+            dest.setFrame(r);
+            return dest;
+        }
+
+        @Override
+        public Rectangle2D createIntersection(Rectangle2D r) {
+            return copy(r);
+        }
+
+        @Override
+        public Rectangle2D createUnion(Rectangle2D r) {
+            return copy(r);
+        }
+
+        @Override
+        public double getX() {
+            return java.lang.Double.NaN;
+        }
+
+        @Override
+        public double getY() {
+            return java.lang.Double.NaN;
+        }
+
+        @Override
+        public double getWidth() {
+            return 0;
+        }
+
+        @Override
+        public double getHeight() {
+            return 0;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return true;
+        }
+
+    }
+
+    private static final UndefinedRectangle UNDEFINED_RECTANGLE = new UndefinedRectangle();
+
+    public static Rectangle2D undefinedRectangle() {
+        return UNDEFINED_RECTANGLE;
+    }
+
+    public static boolean isUndefinedRectangle(Rectangle2D r) {
+        return r == UNDEFINED_RECTANGLE || (r.isEmpty() && Double.isNaN(r.getX()) && Double.isNaN(r.getY()));
+    }
+
 }