]> gerrit.simantics Code Review - simantics/district.git/commitdiff
Hover label profile for district elements. 48/2848/1
authorReino Ruusu <reino.ruusu@semantum.fi>
Tue, 9 Apr 2019 13:13:53 +0000 (16:13 +0300)
committerReino Ruusu <reino.ruusu@semantum.fi>
Thu, 11 Apr 2019 11:00:12 +0000 (14:00 +0300)
Also includes some improvements in edge and vertex rendering and
selection.

gitlab #44

Change-Id: I007153a4ccb0417f9c1ee6a745876d024f5e2c8d

13 files changed:
org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph
org.simantics.district.network.ontology/src/org/simantics/district/network/ontology/DistrictNetworkResource.java
org.simantics.district.network.ui/adapters.xml
org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkEdgeElement.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/adapters/DistrictNetworkVertexElement.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkEdgeNode.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoNode.java [new file with mode: 0644]
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoStyle.java [new file with mode: 0644]
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkNodeUtils.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkVertexNode.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/HoverSensitiveNode.java [new file with mode: 0644]
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java

index a853d85e8058337a52b7d52e2757d4a4193cbc6c..b25be6f5db27b69990f8bd228d3a47f4fddb40da 100644 (file)
@@ -27,6 +27,9 @@ DN.HideStyle : DIA.Style
 DN.VertexSymbolStyle : DIA.Style
 DN.ConnectionLineStyle : DIA.Style
 
+// Style for user component-specified text grid entries
+DN.DistrictNetworkHoverInfoStyle : DIA.Style
+
 // Function for dynamic selection of symbols for a vertex
 // The input of the function is a DN.Vertex
 // The output of the function should be SVG
index a48137cf625bf68cd6ecdf51a6b697d28a4838a1..bb84561785729ed5b258c7fe17c697142537cd4b 100644 (file)
@@ -58,6 +58,7 @@ public class DistrictNetworkResource {
     public final Resource Diagram_splitToMultipleEnabled_Inverse;
     public final Resource Diagram_trackChangesEnabled;
     public final Resource Diagram_trackChangesEnabled_Inverse;
+    public final Resource DistrictNetworkHoverInfoStyle;
     public final Resource DistrictNodeGroup;
     public final Resource DistrictNodeGroup_hasComponentTypeName;
     public final Resource DistrictNodeGroup_hasComponentTypeName_Inverse;
@@ -357,6 +358,7 @@ public class DistrictNetworkResource {
         public static final String Diagram_splitToMultipleEnabled_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/splitToMultipleEnabled/Inverse";
         public static final String Diagram_trackChangesEnabled = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/trackChangesEnabled";
         public static final String Diagram_trackChangesEnabled_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/Diagram/trackChangesEnabled/Inverse";
+        public static final String DistrictNetworkHoverInfoStyle = "http://www.simantics.org/DistrictNetwork-1.0/DistrictNetworkHoverInfoStyle";
         public static final String DistrictNodeGroup = "http://www.simantics.org/DistrictNetwork-1.0/DistrictNodeGroup";
         public static final String DistrictNodeGroup_hasComponentTypeName = "http://www.simantics.org/DistrictNetwork-1.0/DistrictNodeGroup/hasComponentTypeName";
         public static final String DistrictNodeGroup_hasComponentTypeName_Inverse = "http://www.simantics.org/DistrictNetwork-1.0/DistrictNodeGroup/hasComponentTypeName/Inverse";
@@ -666,6 +668,7 @@ public class DistrictNetworkResource {
         Diagram_splitToMultipleEnabled_Inverse = getResourceOrNull(graph, URIs.Diagram_splitToMultipleEnabled_Inverse);
         Diagram_trackChangesEnabled = getResourceOrNull(graph, URIs.Diagram_trackChangesEnabled);
         Diagram_trackChangesEnabled_Inverse = getResourceOrNull(graph, URIs.Diagram_trackChangesEnabled_Inverse);
+        DistrictNetworkHoverInfoStyle = getResourceOrNull(graph, URIs.DistrictNetworkHoverInfoStyle);
         DistrictNodeGroup = getResourceOrNull(graph, URIs.DistrictNodeGroup);
         DistrictNodeGroup_hasComponentTypeName = getResourceOrNull(graph, URIs.DistrictNodeGroup_hasComponentTypeName);
         DistrictNodeGroup_hasComponentTypeName_Inverse = getResourceOrNull(graph, URIs.DistrictNodeGroup_hasComponentTypeName_Inverse);
index 590cb0c693efa1884beb9ea77fe9057f078d4731..77d82eb47321018fc42ec5606bebdf7fe972b551 100644 (file)
         <resource uri="http://www.simantics.org/DistrictNetwork-1.0/ConnectionLineStyle"
             class="org.simantics.district.network.ui.nodes.ConnectionLineStyle">
         </resource>
+        <resource uri="http://www.simantics.org/DistrictNetwork-1.0/DistrictNetworkHoverInfoStyle"
+            class="org.simantics.district.network.ui.nodes.DistrictNetworkHoverInfoStyle">
+            <this />
+        </resource>
     </target>
     
     <target interface="org.simantics.g2d.diagram.DiagramClass">
index d420edc71cd74abe5be18447a2c9cffe2aa0988c..91e48251bb7ed89efc0cf9fb5625a46b6dbbe335 100644 (file)
@@ -3,11 +3,15 @@ package org.simantics.district.network.ui;
 
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.simantics.district.network.ui.adapters.DistrictNetworkEdgeElement;
 import org.simantics.district.network.ui.adapters.DistrictNetworkVertexElement;
+import org.simantics.district.network.ui.nodes.DistrictNetworkEdgeNode;
 import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode;
+import org.simantics.district.network.ui.nodes.HoverSensitiveNode;
 import org.simantics.district.network.ui.nodes.NetworkDrawingNode;
 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
@@ -18,6 +22,7 @@ import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;
 import org.simantics.g2d.element.IElement;
 import org.simantics.scenegraph.Node;
 import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.scenegraph.g2d.IG2DNode;
 import org.simantics.utils.datastructures.hints.IHintContext.Key;
 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
 
@@ -58,30 +63,41 @@ public class NetworkDrawingParticipant extends AbstractDiagramParticipant {
         node.setDiagram(newDiagram);
     }
 
-    public boolean pickHoveredElement(Point2D currentMousePos) {
-        PickRequest req = new PickRequest(currentMousePos).context(getContext());
+    public boolean pickHoveredElement(Point2D currentMousePos, boolean isConnectionTool) {
+        PickRequest req = new PickRequest(new Rectangle2D.Double(currentMousePos.getX(), currentMousePos.getY(), 1e-8, 1e-8)).context(getContext());
         List<IElement> pickables = new ArrayList<IElement>();
         pick.pick(diagram, req, pickables);
         
         List<IElement> snap = new ArrayList<>(diagram.getSnapshot());
         
-        snap.removeAll(pickables);
+        // snap.removeAll(pickables);
         
         boolean changed = false;
-        for (IElement sn : snap) {
-            Node node = sn.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
+        changed = hoverVertexNodes(snap, false, isConnectionTool, changed);
+        changed = hoverEdgeNodes(snap, false, isConnectionTool, changed);
+        changed = hoverVertexNodes(pickables, true, isConnectionTool, changed);
+        changed = hoverEdgeNodes(pickables, true, isConnectionTool, changed);
+        return changed;
+    }
+
+    private boolean hoverVertexNodes(List<IElement> elements, boolean hover, boolean isConnectionTool, boolean changed) {
+        for (IElement elem : elements) {
+            Node node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
             if (node instanceof DistrictNetworkVertexNode) {
-                if (((DistrictNetworkVertexNode) node).hover(false) && !changed) {
-                    changed = true;
-                }
+                changed = ((DistrictNetworkVertexNode) node).hover(hover, isConnectionTool) || changed;
             }
         }
-        
-        for (IElement elem : pickables) {
-            Node node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
-            if (node instanceof DistrictNetworkVertexNode) {
-                if (((DistrictNetworkVertexNode) node).hover(true) && !changed) {
-                    changed = true;
+        return changed;
+    }
+    
+    private boolean hoverEdgeNodes(List<IElement> elements, boolean hover, boolean isConnectionTool, boolean changed) {
+        for (IElement elem : elements) {
+            Node node = elem.getHint(DistrictNetworkEdgeElement.KEY_DN_EDGE_NODE);
+            if (node instanceof DistrictNetworkEdgeNode) {
+                for (IG2DNode n : ((DistrictNetworkEdgeNode) node).getNodes()) {
+                    if (n instanceof HoverSensitiveNode) {
+                        changed = ((HoverSensitiveNode)n).hover(hover, isConnectionTool) || changed;
+                    }
                 }
             }
         }
index 34424739eb9a0764dbab3d7338a183b86994ff29..ef2e21fed709518ca5c7c21075018526f0474dc6 100644 (file)
@@ -4,6 +4,8 @@ import java.awt.Color;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 import java.util.Collection;
@@ -29,6 +31,7 @@ import org.simantics.g2d.element.handler.impl.SimpleElementLayers;
 import org.simantics.maps.MapScalingTransform;
 import org.simantics.scenegraph.g2d.G2DParentNode;
 import org.simantics.scenegraph.g2d.nodes.SVGNode;
+import org.simantics.scenegraph.utils.NodeUtil;
 import org.simantics.utils.datastructures.hints.IHintContext.Key;
 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
 import org.slf4j.Logger;
@@ -129,7 +132,7 @@ public class DistrictNetworkEdgeElement {
                 Rectangle2D bounds = getBounds(s);
                 switch (policy) {
                 case PICK_CONTAINED_OBJECTS:    return pickContainedObjects(edge, bounds);
-                case PICK_INTERSECTING_OBJECTS: return pickIntersectingObjects(edge, bounds);
+                case PICK_INTERSECTING_OBJECTS: return pickIntersectingObjects(e, edge, bounds);
                 }
                 return false;
             }
@@ -162,21 +165,54 @@ public class DistrictNetworkEdgeElement {
             return eminx >= bsminx && eminy >= boundsMinY && emaxx <= bsmaxx && emaxy <= boundsMaxY;
         }
 
-        private boolean pickIntersectingObjects(DistrictNetworkEdge edge, Rectangle2D bounds) {
-            double tolerance = (bounds.getHeight() + bounds.getHeight()) * 1 / MapScalingTransform.getScaleX();
-            Line2D line = new Line2D.Double(edge.getStartPoint(), edge.getEndPoint());
+        private boolean pickIntersectingObjects(IElement e, DistrictNetworkEdge edge, Rectangle2D bounds) {
+            double dx = bounds.getWidth() / MapScalingTransform.getScaleX();
+            double dy = bounds.getHeight() / MapScalingTransform.getScaleY();
+            
+            // Half the diagonal + half of the line width
+            DistrictNetworkEdgeNode node = e.getHint(KEY_DN_EDGE_NODE);
+            AffineTransform at = NodeUtil.getLocalToGlobalTransform(node);
+            
+            Path2D path = node.getPath();
+            if (path == null)
+                return false;
+            
+            double lineWidth = node.getStrokeWidth(at, true);
+            double tolerance = Math.sqrt(dx * dx + dy * dy) / 2 + lineWidth / 2;
+            
             double sx = bounds.getCenterX() / MapScalingTransform.getScaleX();
             double sy = bounds.getCenterY() / MapScalingTransform.getScaleY();
-            double ssx = ModelledCRS.xToLongitude(sx);
-            double ssy = ModelledCRS.yToLatitude(-sy); // Invert for Simantics diagram coordinate system
-            double distSq = line.ptSegDistSq(ssx, ssy);
-//            System.out.println("s: " + sx + ", " + sy);
-//            System.out.println("ss: " + ssx + ", " + ssy);
-//            System.out.println("p1: " + edge.getStartPoint());
-//            System.out.println("p2: " + edge.getEndPoint());
-//            System.out.println("line: " + "(" + line.getX1() + ", " + line.getY1() + ", " + line.getX2() + ", " + line.getY2() + ")");
-//            System.out.println("distance from line is " + Math.sqrt(distSq) + " with tolerance " + tolerance);
-            return distSq <= tolerance * tolerance;
+            
+            double coords[] = new double[6];
+            Point2D prevPoint = new Point2D.Double(), curPoint = new Point2D.Double();
+            Line2D line = new Line2D.Double();
+            for (PathIterator it = path.getPathIterator(null); !it.isDone(); it.next()) {
+                int type = it.currentSegment(coords);
+                switch (type) {
+                case PathIterator.SEG_MOVETO:
+                    curPoint.setLocation(coords[0], coords[1]);
+                    break;
+                case PathIterator.SEG_LINETO:
+                    prevPoint.setLocation(curPoint);
+                    curPoint.setLocation(coords[0], coords[1]);
+                    line.setLine(prevPoint, curPoint);
+                    double distSq = line.ptSegDistSq(sx, sy);
+//                    System.out.println("s: " + sx + ", " + sy);
+//                    System.out.println("ss: " + ssx + ", " + ssy);
+//                    System.out.println("p1: " + edge.getStartPoint());
+//                    System.out.println("p2: " + edge.getEndPoint());
+//                    System.out.println("line: " + "(" + line.getX1() + ", " + line.getY1() + ", " + line.getX2() + ", " + line.getY2() + ")");
+//                    System.out.println("distance from line is " + Math.sqrt(distSq) + " with tolerance " + tolerance);
+                    if (distSq <= tolerance * tolerance)
+                        return true; 
+                    break;
+                default:
+                    LOGGER.error("Invalid edge path", new IllegalStateException());
+                    return false;
+                }
+            }
+            
+            return false;
         }
 
         private Rectangle2D getBounds(Shape shape) {
index a989c56117644025e9b883620f1af29acf57ff5e..1ff5eefa407c7c75a3e978b9531232a23c067bdd 100644 (file)
@@ -115,9 +115,6 @@ public class DistrictNetworkVertexElement {
         public boolean pickTest(IElement e, Shape s, PickPolicy policy) {
             DistrictNetworkVertexNode node = e.getHint(KEY_DN_VERTEX_NODE);
             Rectangle2D boundsInLocal = node.getBounds();
-            ICanvasContext ctx = DiagramNodeUtil.getCanvasContext(node);
-            AffineTransform canvasTransform = ctx.getHintStack().getHint(Hints.KEY_CANVAS_TRANSFORM);
-            Rectangle2D scaledBounds = new Rectangle2D.Double(boundsInLocal.getX(), boundsInLocal.getY(), boundsInLocal.getWidth() / canvasTransform.getScaleX() * 2, boundsInLocal.getHeight() / canvasTransform.getScaleY() * 2);
             Rectangle2D bounds = getBounds(s);
             switch (policy) {
             case PICK_CONTAINED_OBJECTS:
index 74e8acdc575fa79a833ab38e92e56d2fda0324e2..61aec5ce55cc8285ad64b8b8fafc67984bc3c463 100644 (file)
@@ -79,10 +79,9 @@ public class DistrictNetworkEdgeNode extends G2DParentNode implements ISelection
         BasicStroke bs = null;
         double scale = 1.0;
         if (scaleStroke) {
-            scale = GeometryUtils.getScale(g2d.getTransform());
-            scale = Math.max(10000, Math.min(scale, 50000));
-            double str = stroke != null ? Math.abs(stroke) : 1.0;
-            bs = GeometryUtils.scaleStroke(STROKE, (float) (str / scale));
+            AffineTransform tr = g2d.getTransform();
+            scale = DistrictNetworkNodeUtils.getScale(tr);
+            bs = GeometryUtils.scaleStroke(STROKE, getStrokeWidth(scale));
         } else {
             bs = STROKE;
         }
@@ -91,7 +90,7 @@ public class DistrictNetworkEdgeNode extends G2DParentNode implements ISelection
 
         if (isSelected()) {
             g2d.setColor(SELECTION_COLOR);
-            g2d.setStroke(GeometryUtils.scaleStroke(bs, 4f));
+            g2d.setStroke(GeometryUtils.scaleAndOffsetStrokeWidth(bs, 1.f, (float)(2 * STROKE.getLineWidth() / scale)));
             g2d.draw(path);
         }
 
@@ -157,6 +156,28 @@ public class DistrictNetworkEdgeNode extends G2DParentNode implements ISelection
             g2d.setTransform(ot);
     }
 
+    public float getStrokeWidth(AffineTransform tr, boolean selection) {
+        double scale = DistrictNetworkNodeUtils.getScale(tr);
+        float width = STROKE.getLineWidth() * getStrokeWidth(scale);
+        if (selection) width = width + (float) (2 * STROKE.getLineWidth() / scale);
+        return width;
+    }
+    
+    private float getStrokeWidth(double scale) {
+        if (scaleStroke) {
+            double str = stroke != null ? Math.abs(stroke) : 1.0;
+            float strokeWidth = (float) (str / scale);
+            return strokeWidth;
+        }
+        else {
+            return 1.f;
+        }
+    }
+
+    public Path2D getPath() {
+        return path;
+    }
+    
     private Point2D getCenterPoint() {
         if (centerPoint == null)
             centerPoint = new Point2D.Double();
diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoNode.java
new file mode 100644 (file)
index 0000000..cb7053a
--- /dev/null
@@ -0,0 +1,109 @@
+package org.simantics.district.network.ui.nodes;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.simantics.scenegraph.g2d.G2DNode;
+import org.simantics.scl.runtime.Lists;
+import org.simantics.scl.runtime.tuple.Tuple3;
+
+public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensitiveNode {
+
+       private static final Font FONT = new Font(Font.DIALOG, Font.PLAIN, 12);
+
+       private static final long serialVersionUID = 1L;
+
+       public static final String NODE_KEY = "DISTRICT_NETWORK_HOVER_INFO";
+
+       private static final int W1 = 50;
+       private static final int W2 = 30;
+       private static final int PAD = 5;
+
+       private List<Tuple3> labels;
+
+       private Point2D origin;
+
+       private boolean hover = false;
+       
+       private static AtomicReference<DistrictNetworkHoverInfoNode> activeNode = new AtomicReference<>();
+
+       @Override
+       public void render(Graphics2D g) {
+               if (!hover || activeNode.get() != this)
+                       return;
+
+               AffineTransform ot = g.getTransform();
+               Font of = g.getFont();
+               doRender(g);
+               g.setFont(of);
+               g.setTransform(ot);
+       }
+
+       private void doRender(Graphics2D g) {
+               g.translate(origin.getX(), origin.getY());
+               double scale = 1.5 / g.getTransform().getScaleX();
+               g.scale(scale, scale);
+
+               g.setFont(FONT);
+               double rowHeight = g.getFontMetrics().getHeight() * 1.1;
+
+               g.setColor(Color.BLACK);
+               
+               for (Tuple3 t : labels) {
+                       g.translate(0.f, -rowHeight);
+                       
+                       if (t.c0 != null) {
+                               g.drawString((String) t.c0, -(W1 + PAD + W2), 0.f);
+                       }
+                       
+                       if (t.c1 != null) {
+                               int width1 = g.getFontMetrics().stringWidth((String) t.c1);
+                               g.drawString((String) t.c1, - width1, 0.f);
+                       }
+                       
+                       if (t.c2 != null) {
+                               g.drawString((String) t.c2, PAD, 0.f);
+                       }
+               }
+       }
+
+       @Override
+       public Rectangle2D getBoundsInLocal() {
+               return null;
+       }
+
+       @SuppressWarnings("unchecked")
+       public void setLabels(List<Tuple3> list) {
+               this.labels = Lists.reverse(list);
+       }
+
+       public void setOrigin(Point2D origin) {
+               this.origin = origin;
+       }
+
+       @Override
+       public boolean hover(boolean hover, boolean isConnectionTool) {
+               hover = hover && activeNode.updateAndGet(current -> current == null ? this : current) == this;
+               boolean changed = hover != this.hover;
+               this.hover = hover;
+               
+               if (changed) {
+                       if (!hover) activeNode.updateAndGet(current -> current == this ? null : current);
+                       repaint();
+               }
+               
+               return changed;
+       }
+       
+       @Override
+       public void delete() {
+               super.delete();
+               activeNode.getAndUpdate(current -> current == this ? null : current);
+       }
+}
diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoStyle.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoStyle.java
new file mode 100644 (file)
index 0000000..590903e
--- /dev/null
@@ -0,0 +1,176 @@
+package org.simantics.district.network.ui.nodes;
+
+import java.awt.geom.Point2D;
+import java.util.Collections;
+import java.util.List;
+
+import org.simantics.Simantics;
+import org.simantics.databoard.Bindings;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.procedure.adapter.TransientCacheListener;
+import org.simantics.db.common.request.ResourceRead;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.exception.PendingVariableException;
+import org.simantics.db.layer0.util.Layer0Utils;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.diagram.profile.StyleBase;
+import org.simantics.diagram.stubs.DiagramResource;
+import org.simantics.district.network.DistrictNetworkUtil;
+import org.simantics.district.network.ontology.DistrictNetworkResource;
+import org.simantics.layer0.Layer0;
+import org.simantics.modeling.ModelingResources;
+import org.simantics.scenegraph.INode;
+import org.simantics.scenegraph.profile.EvaluationContext;
+import org.simantics.scenegraph.profile.common.ProfileVariables;
+import org.simantics.scl.compiler.top.ValueNotFound;
+import org.simantics.scl.osgi.SCLOsgi;
+import org.simantics.scl.runtime.SCLContext;
+import org.simantics.scl.runtime.function.Function1;
+import org.simantics.scl.runtime.tuple.Tuple3;
+import org.simantics.structural.stubs.StructuralResource2;
+
+public class DistrictNetworkHoverInfoStyle extends StyleBase<DistrictNetworkHoverInfoStyle.StyleResult> {
+
+       private static final String ACTIONS_MODULE = "Actions";
+       private static final String HOVER_CONTRIBUTION = "hoverContribution";
+
+       public class StyleResult {
+               Point2D origin;
+               List<Tuple3> labels;
+
+               public StyleResult(Point2D origin, List<Tuple3> labels) {
+                       this.origin = origin;
+                       this.labels = labels;
+               }
+
+               public Point2D getOrigin() {
+                       return origin;
+               }
+
+               public List<Tuple3> getLabels() {
+                       return labels;
+               }
+       }
+       
+       public DistrictNetworkHoverInfoStyle(Resource style) throws DatabaseException {
+               super(style);
+       }
+       
+       String currentRowKey;
+       
+       protected Resource getConfigurationComponent(ReadGraph graph, Resource element) throws DatabaseException {
+               ModelingResources MOD = ModelingResources.getInstance(graph);
+               DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
+               
+               Resource mappedElement = graph.getPossibleObject(element, DN.MappedComponent);
+               return mappedElement != null ? graph.getPossibleObject(mappedElement, MOD.ElementToComponent) : null;
+       }
+       
+       @Override
+       public StyleResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry,
+                       Resource mapElement, Variable configuration) throws DatabaseException {
+               DiagramResource DIA = DiagramResource.getInstance(graph);
+               StructuralResource2 STR = StructuralResource2.getInstance(graph);
+
+               String variableURI = graph.getPossibleRelatedValue(runtimeDiagram, DIA.RuntimeDiagram_HasVariable, Bindings.STRING);
+               Variable activeVariable = org.simantics.db.layer0.variable.Variables.getPossibleVariable(graph, variableURI);
+               if (activeVariable == null)
+                       return null;
+
+               Resource module = DistrictNetworkUtil.getMappedComponentCached(graph, mapElement);
+               if (module == null)
+                       return null;
+
+               Resource moduleType = graph.getPossibleType(module, STR.Component);
+               if (moduleType == null)
+                       return null;
+               
+               Function1<Variable, List<Tuple3>> function = getUCTextGridFunctionCached(graph, moduleType);
+               if (function == null)
+                       return null;
+               
+               List<Tuple3> result;
+               try {
+                       Variable variable = Variables.getVariable(graph, module);
+                       Variable moduleVariable = Variables.possibleActiveVariable(graph, variable);
+                       if (moduleVariable == null)
+                               moduleVariable = variable;
+
+                       result = Simantics.applySCLRead(graph, function, moduleVariable);
+               } catch (PendingVariableException e) {
+                       result = Collections.singletonList(new Tuple3("<pending>", "", ""));
+               }
+               
+               Point2D point;
+               DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
+               if (graph.isInstanceOf(mapElement, DN.Vertex)) {
+                       double[] coords = graph.getRelatedValue(mapElement, DIA.HasLocation);
+                       point = DistrictNetworkNodeUtils.calculatePoint2D(new Point2D.Double(coords[0], coords[1]), null);
+               }
+               else if (graph.isInstanceOf(mapElement, DN.Edge)) {
+                       Resource v1 = graph.getSingleObject(mapElement, DN.HasStartVertex);
+                       double[] coords1 = graph.getRelatedValue(v1, DIA.HasLocation);
+                       Resource v2 = graph.getSingleObject(mapElement, DN.HasEndVertex);
+                       double[] coords2 = graph.getRelatedValue(v2, DIA.HasLocation);
+                       point = DistrictNetworkNodeUtils.calculatePoint2D(new Point2D.Double((coords1[0] + coords2[0]) / 2, (coords1[1] + coords2[1]) / 2), null);
+               }
+               else {
+                       return null;
+               }
+               
+               return new StyleResult(point, result);
+       }
+       
+       @Override
+       public void applyStyleForNode(EvaluationContext observer, INode parent, StyleResult results) {
+               if (results == null) {
+                       cleanupStyleForNode(observer, parent);
+                       return;
+               }
+               
+               DistrictNetworkHoverInfoNode node = ProfileVariables.claimChild(parent, "*", DistrictNetworkHoverInfoNode.NODE_KEY, DistrictNetworkHoverInfoNode.class, observer);
+               if (node == null)
+                       return;
+               
+               node.setLabels(results.getLabels());
+               node.setOrigin(results.getOrigin());
+       }
+       
+       @Override
+       protected void cleanupStyleForNode(EvaluationContext observer, INode node) {
+               ProfileVariables.denyChild(node, "*", DistrictNetworkHoverInfoNode.NODE_KEY);
+       }
+       
+       private static Function1<Variable, List<Tuple3>> getUCTextGridFunctionCached(ReadGraph graph, Resource componentType)
+                       throws DatabaseException {
+               return graph.syncRequest(new UCTextGridFunctionRequest(componentType), TransientCacheListener.instance());
+       }
+       
+       private static final class UCTextGridFunctionRequest extends ResourceRead<Function1<Variable, List<Tuple3>>> {
+               public UCTextGridFunctionRequest(Resource resource) {
+                       super(resource);
+               }
+
+               @SuppressWarnings("unchecked")
+               @Override
+               public Function1<Variable, List<Tuple3>> perform(ReadGraph graph) throws DatabaseException {
+                       Resource actionsModule = Layer0Utils.getPossibleChild(graph, resource, ACTIONS_MODULE);
+                       if (actionsModule == null || !graph.isInstanceOf(actionsModule, Layer0.getInstance(graph).SCLModule))
+                               return null;
+                       
+                       String uri = graph.getURI(actionsModule);
+                       SCLContext sclContext = SCLContext.getCurrent();
+                       Object oldGraph = sclContext.get("graph");
+                       try {
+                               sclContext.put("graph", graph);
+                               return (Function1<Variable, List<Tuple3>>) SCLOsgi.MODULE_REPOSITORY.getValue(uri, HOVER_CONTRIBUTION);
+                       } catch (ValueNotFound e1) {
+                               return null;
+                       } finally {
+                               sclContext.put("graph", oldGraph);
+                       }
+               }
+       }
+}
index 20479a781471ab968c0fe5b1c334c80b852a6e1f..21e49b58277c8f93334ddcf1ccf6428363f278dc 100644 (file)
@@ -6,6 +6,7 @@ import java.awt.geom.Rectangle2D;
 
 import org.simantics.district.network.ModelledCRS;
 import org.simantics.maps.MapScalingTransform;
+import org.simantics.scenegraph.utils.GeometryUtils;
 
 public class DistrictNetworkNodeUtils {
 
@@ -38,7 +39,14 @@ public class DistrictNetworkNodeUtils {
 
     public static double calculateScaleRecip(AffineTransform tr) {
         int zoomLevel = MapScalingTransform.zoomLevel(tr);
-        double t = 1.0 / Math.sqrt(zoomLevel);
+        double t = 1.0 / (getScale(tr) * Math.sqrt(zoomLevel));
         return t;
     }
+
+    static double getScale(AffineTransform tr) {
+        double scale;
+        scale = GeometryUtils.getScale(tr);
+        scale = Math.max(4096, Math.min(scale, 32768));
+        return scale;
+    }
 }
index 929ad9353ebd72d87b37b41d02e2373e639fc8d2..0533e3117bf38b32a4f94191139fe55d8876e148 100644 (file)
@@ -9,30 +9,32 @@ import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 
 import org.simantics.district.network.ui.adapters.DistrictNetworkVertex;
+import org.simantics.maps.MapScalingTransform;
 import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.ISelectionPainterNode;
 import org.simantics.scenegraph.g2d.G2DNode;
 import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.scenegraph.g2d.IG2DNode;
 import org.simantics.scenegraph.g2d.nodes.SVGNode;
 import org.simantics.scenegraph.utils.GeometryUtils;
 import org.simantics.scenegraph.utils.NodeUtil;
 
-public class DistrictNetworkVertexNode extends G2DParentNode implements ISelectionPainterNode {
+public class DistrictNetworkVertexNode extends G2DParentNode implements ISelectionPainterNode, HoverSensitiveNode {
 
     //private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkVertexNode.class);
 
     private static final long serialVersionUID = -2641639101400236719L;
 
-    private static final double left = -0.00005;
+    private static final double left = -15;
     private static final double top = left;
-    public static final double width = 0.0001;
+    public static final double width = 30;
     private static final double height = width;
 
     private static final BasicStroke STROKE           = new BasicStroke((float)width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
     private static final Color       SELECTION_COLOR  = new Color(255, 0, 255, 96);
 
     private static final Rectangle2D NORMAL = new Rectangle2D.Double(left, top, width, height);
-    private static final Rectangle2D HOVERED = new Rectangle2D.Double(left * 3, top * 3, width * 3, height * 3);
+    private static final Rectangle2D HOVERED = new Rectangle2D.Double(left * 2, top * 2, width * 2, height * 2);
 
     private DistrictNetworkVertex vertex;
 
@@ -47,7 +49,7 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti
     private transient Rectangle2D rect;
     private transient AffineTransform symbolTransform;
 
-    private double nodeSize = 3;
+    private double nodeSize = 1.0;
 
     @Override
     public void init() {
@@ -90,7 +92,7 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti
         if (NodeUtil.isSelected(this, 1)) {
             changeColor = true;
             g2d.setColor(SELECTION_COLOR);
-            BasicStroke ss = GeometryUtils.scaleStroke(STROKE, (float) (viewScaleRecip * nodeSize));
+            BasicStroke ss = GeometryUtils.scaleStroke(STROKE, (float)viewScaleRecip);
             g2d.setStroke(ss);
             g2d.draw(toDraw);
         }
@@ -127,6 +129,7 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti
 
     @Override
     public Rectangle2D getBoundsInLocal() {
+        updateBounds();
         return bounds;
     }
 
@@ -151,12 +154,17 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti
 
     private Rectangle2D calculateBounds(Rectangle2D rect) {
         Point2D calcPoint = DistrictNetworkNodeUtils.calculatePoint2D(vertex.getPoint(), point);
-        AffineTransform at = getTransform();
+        AffineTransform at = NodeUtil.getLocalToGlobalTransform(this);
+        at.concatenate(MapScalingTransform.INSTANCE);
         double x = calcPoint.getX();
         double y = calcPoint.getY();
-        double widthh = width / at.getScaleX();
-        double heighth = height / at.getScaleY();
-        return new Rectangle2D.Double(x - widthh, y - heighth, widthh * 2, heighth * 2).getBounds2D();
+        double scaleRecip = DistrictNetworkNodeUtils.calculateScaleRecip(at);
+        double widthh = width * scaleRecip * nodeSize;
+        double heighth = height * scaleRecip * nodeSize;
+        if (rect == null)
+            rect = new Rectangle2D.Double();
+        rect.setRect(x - widthh/2, y - heighth/2, widthh, heighth);
+        return rect;
     }
 
     public void setVertex(DistrictNetworkVertex vertex) {
@@ -164,14 +172,18 @@ public class DistrictNetworkVertexNode extends G2DParentNode implements ISelecti
         updateBounds();
     }
 
-    public boolean hover(boolean hover) {
-//        if (hover && LOGGER.isDebugEnabled())
-//            LOGGER.debug("Hovering " + this);
-        boolean changed = false;
-        if (this.hover != hover) {
-            this.hover = hover;
-            changed = true;
+    @Override
+    public boolean hover(boolean hover, boolean isConnectionTool) {
+        // Only react to hover when the connection tool is active
+        boolean doHover = hover && isConnectionTool;
+        boolean changed = this.hover != doHover;
+        this.hover = doHover;
+        
+        for (IG2DNode child : getNodes()) {
+            if (child instanceof HoverSensitiveNode)
+                changed = ((HoverSensitiveNode)child).hover(hover, isConnectionTool) || changed;
         }
+        
         return changed;
     }
 
diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/HoverSensitiveNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/HoverSensitiveNode.java
new file mode 100644 (file)
index 0000000..bf76785
--- /dev/null
@@ -0,0 +1,5 @@
+package org.simantics.district.network.ui.nodes;
+
+public interface HoverSensitiveNode {
+    boolean hover(boolean hover, boolean isConnectionTool);
+}
index 524bf7221e42133f76b0644130760af8fd43842a..00728e894e5f64c398c57ec3e86b953bff5bd81c 100644 (file)
@@ -276,22 +276,21 @@ public class NetworkDrawingNode extends G2DNode {
     @Override
     protected boolean mouseMoved(MouseMovedEvent e) {
         IToolMode mode = getToolMode();
-        if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
-            boolean repaint = false;
-            Point2D p = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
-            if (participant.pickHoveredElement(p)) {
-                repaint = true;
-            }
-            if (!nodes.isEmpty()) {
-                currentMousePos = p;
-                
-                repaint();
-                return true;
-            }
-            currentMousePos = null;
-            if (repaint == true)
-                repaint();
+        boolean repaint = false;
+        Point2D p = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
+        boolean isConnectionTool = mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK);
+        if (participant.pickHoveredElement(p, isConnectionTool)) {
+            repaint = true;
+        }
+        if (!nodes.isEmpty()) {
+            currentMousePos = p;
+            
+            repaint();
+            return true;
         }
+        currentMousePos = null;
+        if (repaint == true)
+            repaint();
         return super.mouseMoved(e);
     }