]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java
Usability fixes for district network node hover info showing
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / NetworkDrawingParticipant.java
index c020c33d67e65abae9788aa9a3ea761e929c9e53..e5ce207e51af69f3760724a92c5697aa3748d591 100644 (file)
@@ -3,89 +3,155 @@ 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.Collections;
+import java.util.Comparator;
 import java.util.List;
 
+import org.simantics.db.Resource;
+import org.simantics.diagram.ui.DiagramModelHints;
+import org.simantics.district.network.ui.adapters.DistrictNetworkEdgeElement;
 import org.simantics.district.network.ui.adapters.DistrictNetworkVertexElement;
 import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode;
 import org.simantics.district.network.ui.nodes.NetworkDrawingNode;
+import org.simantics.district.network.ui.participants.DynamicVisualisationContributionsParticipant;
 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
 import org.simantics.g2d.diagram.IDiagram;
 import org.simantics.g2d.diagram.handler.PickContext;
 import org.simantics.g2d.diagram.handler.PickRequest;
 import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;
+import org.simantics.g2d.element.ElementHints;
 import org.simantics.g2d.element.IElement;
+import org.simantics.maps.MapScalingTransform;
+import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.Node;
 import org.simantics.scenegraph.g2d.G2DParentNode;
-import org.simantics.utils.datastructures.hints.IHintContext.Key;
-import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;
+import org.simantics.scenegraph.utils.GeometryUtils;
 
 public class NetworkDrawingParticipant extends AbstractDiagramParticipant {
 
+    public static final String NETWORK_DRAWING_NODE = "networkDrawingNode";
+
     @Dependency
     PickContext pick;
-    
-    /**
-     * A hint key for terminal pick distance in control pixels.
-     * @see #PICK_DIST
-     */
-    public static final Key KEY_PICK_DISTANCE = new KeyOf(Double.class, "PICK_DISTANCE");
+
+    private NetworkDrawingNode node;
+    private DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant;
+    private AffineTransform transform;
 
     /**
-     * Default terminal pick distance in control pixels.
-     * @see #DEFAULT_PICK_DISTANCE
+     * Holds the current element for which hover information is shown.
+     * This is just to optimize the 
      */
-    public static final double PICK_DIST = 10;
-    
-    private NetworkDrawingNode node;
+    private IElement currentHoverElement;
 
-    private AffineTransform transform;
-    
-    public NetworkDrawingParticipant(AffineTransform transform) {
+    public NetworkDrawingParticipant(DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant, AffineTransform transform) {
+        this.dynamicVisualisationContributionsParticipant = dynamicVisualisationContributionsParticipant;
         this.transform = transform;
     }
 
     @SGInit
     public void initSG(G2DParentNode parent) {
-        node = parent.addNode("networkDrawingNode", NetworkDrawingNode.class);
+        node = parent.addNode(NETWORK_DRAWING_NODE, NetworkDrawingNode.class);
         node.setTransform(transform);
         node.setNetworkDrawingParticipant(this);
     }
-    
+
     @Override
     protected void onDiagramSet(IDiagram newDiagram, IDiagram oldDiagram) {
         node.setDiagram(newDiagram);
     }
 
-    public boolean pickHoveredElement(Point2D currentMousePos) {
-        PickRequest req = new PickRequest(currentMousePos.getX(), currentMousePos.getY()).context(getContext());
-        List<IElement> pickables = new ArrayList<IElement>();
+    public boolean pickHoveredElement(Point2D canvasPos, boolean isConnectionTool, AffineTransform viewTransform) {
+        PickRequest req = new PickRequest(getPickRect(canvasPos, viewTransform)).context(getContext());
+        List<IElement> pickables = new ArrayList<>();
         pick.pick(diagram, req, pickables);
         
-        List<IElement> snap = new ArrayList<>(diagram.getSnapshot());
-        
-        snap.removeAll(pickables);
-        
-        boolean changed = false;
-        for (IElement sn : snap) {
-            Node node = sn.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
-            if (node instanceof DistrictNetworkVertexNode) {
-                if (((DistrictNetworkVertexNode) node).hover(false) && !changed) {
-                    changed = true;
-                }
+
+        Comparator<IElement> nearestVerticesFirst = (IElement e1, IElement e2) -> {
+            // If there are any vertices in the elements, prefer those primarily.
+            DistrictNetworkVertexNode v1 = e1.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
+            DistrictNetworkVertexNode v2 = e2.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
+
+            // Don't reorder edges
+            if ((v1 == null && v2 == null))
+                return 0;
+
+            // Sort vertices in nearest first order
+            if (v1 != null && v2 != null) {
+                Rectangle2D b1 = v1.getBounds();
+                Rectangle2D b2 = v2.getBounds();
+                double dist1 = canvasPos.distanceSq(b1.getCenterX(), b1.getCenterY());
+                double dist2 = canvasPos.distanceSq(b2.getCenterX(), b2.getCenterY());
+                return dist1 < dist2 ? -1 : dist1 > dist2 ? 1 : 0;
             }
+
+            // Always vertices before edges
+            return v1 != null && v2 == null ? -1 : 1;
+        };
+
+        Collections.sort(pickables, nearestVerticesFirst);
+
+        updateHoveredElement(pickables, true, isConnectionTool, viewTransform);
+        // Will repaint once the async hover info calculation is ready, no need to do it here
+        return false;
+    }
+
+    private boolean updateHoveredElement(List<IElement> elements, boolean hover, boolean isConnectionTool, AffineTransform viewTransform) {
+        if (elements == null || elements.isEmpty()) {
+            currentHoverElement = null;
+            return dynamicVisualisationContributionsParticipant.doHover(false, isConnectionTool);
+        } else {
+            dynamicVisualisationContributionsParticipant.doHover(true, isConnectionTool);
+
+            // we prefer the first picked element only
+            IElement elem = elements.get(0);
+            if (elem.equals(currentHoverElement))
+                return false;
+
+            INode node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
+            if (node == null)
+                node = elem.getHint(DistrictNetworkEdgeElement.KEY_DN_EDGE_NODE);
+            if (node == null)
+                return false;
+
+            Resource mapElement = elem.getHint(ElementHints.KEY_OBJECT);
+            Resource runtimeDiagram = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);
+            currentHoverElement = elem;
+            dynamicVisualisationContributionsParticipant.hoverNode(runtimeDiagram, mapElement, node, MapScalingTransform.zoomLevel(viewTransform));
+            return true;
         }
-        
+    }
+
+    public boolean isHoveringOverNode(Point2D canvasPos, AffineTransform viewTransform) {
+        PickRequest req = new PickRequest(getPickRect(canvasPos, viewTransform)).context(getContext());
+        List<IElement> pickables = new ArrayList<>();
+        pick.pick(diagram, req, pickables);
         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 true;
             }
         }
-        return changed;
+        return false;
+    }
+
+    private Rectangle2D getPickRect(Point2D canvasPos, AffineTransform viewTransform) {
+        double pixelScale = 1.0 / GeometryUtils.getScale(viewTransform);
+        if (Double.isInfinite(pixelScale))
+            pixelScale = 1e-8;
+
+        Rectangle2D pickRect = GeometryUtils.expandRectangle(
+                new Rectangle2D.Double(canvasPos.getX(), canvasPos.getY(), 0, 0),
+                pixelScale * 4);
+
+        return pickRect;
+    }
+
+    public AffineTransform getTransform() {
+        return transform;
     }
 
 }