]> gerrit.simantics Code Review - simantics/district.git/commitdiff
Usability fixes for district network node hover info showing 50/3650/1
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 29 Nov 2019 14:04:42 +0000 (16:04 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Fri, 29 Nov 2019 14:21:21 +0000 (16:21 +0200)
Previously there was really no logic with what is shown if the cursor
was on top of multiple elements at the same time.

Now the hovering logic always prefers the closest vertex that is picked
from near the mouse cursor and only if there are no nearby vertices,
will edges be selected. Picking also takes the current view zoom into
account properly which it didn't do before.

Also includes some code cleanup.

gitlab #44

Change-Id: I8696ff12853f0de2040db91909a1c4512fe4b2fe
(cherry picked from commit 86d471d96d6bc11bf7629113e57c6d9a9916e608)

org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph
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/nodes/DistrictNetworkHoverInfoNode.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DynamicVisualisationContributionsParticipant.java
org.simantics.district.network.ui/src/org/simantics/district/network/ui/styles/DistrictNetworkHoverInfoStyle.java

index d17219de171b6a474ee4dc5e72c3b0c8521d3158..56488bface216ef92297291f6d6b89b37af0e7e6 100644 (file)
@@ -31,9 +31,6 @@ DN.VertexSymbolStyle : DIA.Style
 DN.ConnectionLineStyle : DIA.Style
 DN.ElevationRectangleStyle : DIA.Style
 
-// Style for user component-specified text grid entries
-DN.DistrictNetworkHoverInfoStyle : DIA.Style
-
 // Style for user component-specified static info text for network branches
 DN.DistrictNetworkStaticInfoStyle : DIA.Style
 
index f4dea68aa515a0ac4ee597b6c165a8902cbf1851..1699360561e87f6370fde46c874eee953ea5c1d5 100644 (file)
         <resource uri="http://www.simantics.org/DistrictNetwork-1.0/ConnectionLineStyle"
             class="org.simantics.district.network.ui.styles.ConnectionLineStyle">
         </resource>
-        <resource uri="http://www.simantics.org/DistrictNetwork-1.0/DistrictNetworkHoverInfoStyle"
-            class="org.simantics.district.network.ui.styles.DistrictNetworkHoverInfoStyle">
-            <this />
-        </resource>
         <resource uri="http://www.simantics.org/DistrictNetwork-1.0/DistrictNetworkStaticInfoStyle"
             class="org.simantics.district.network.ui.styles.DistrictNetworkStaticInfoStyle">
             <this />
index 77ec735f6d2cc14c9f6013127244b6e82fac3ace..e5ce207e51af69f3760724a92c5697aa3748d591 100644 (file)
@@ -5,15 +5,15 @@ 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.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.district.network.ui.participants.DynamicVisualisationContributionsParticipant;
 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
@@ -24,36 +24,29 @@ 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.scenegraph.g2d.IG2DNode;
-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
+    @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");
 
-    /**
-     * Default terminal pick distance in control pixels.
-     * @see #DEFAULT_PICK_DISTANCE
-     */
-    public static final double PICK_DIST = 10;
-    
     private NetworkDrawingNode node;
-
     private DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant;
     private AffineTransform transform;
-    
+
+    /**
+     * Holds the current element for which hover information is shown.
+     * This is just to optimize the 
+     */
+    private IElement currentHoverElement;
+
     public NetworkDrawingParticipant(DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant, AffineTransform transform) {
         this.dynamicVisualisationContributionsParticipant = dynamicVisualisationContributionsParticipant;
         this.transform = transform;
@@ -65,77 +58,76 @@ public class NetworkDrawingParticipant extends AbstractDiagramParticipant {
         node.setTransform(transform);
         node.setNetworkDrawingParticipant(this);
     }
-    
+
     @Override
     protected void onDiagramSet(IDiagram newDiagram, IDiagram oldDiagram) {
         node.setDiagram(newDiagram);
     }
 
-    public boolean pickHoveredElement(Point2D currentMousePos, boolean isConnectionTool) {
-        PickRequest req = new PickRequest(new Rectangle2D.Double(currentMousePos.getX(), currentMousePos.getY(), 1e-8, 1e-8)).context(getContext());
+    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);
+        
+
+        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;
+        };
 
-        List<IElement> snap = diagram.getSnapshot();
+        Collections.sort(pickables, nearestVerticesFirst);
 
-        hoverNodes2(pickables, true, isConnectionTool, currentMousePos);
-        // we repaint ourselves once the async calulation is ready
+        updateHoveredElement(pickables, true, isConnectionTool, viewTransform);
+        // Will repaint once the async hover info calculation is ready, no need to do it here
         return false;
-        
-//        boolean changed = false;
-//        changed |= hoverNodes(snap, false, isConnectionTool, currentMousePos);
-//        changed |= hoverNodes(pickables, true, isConnectionTool, currentMousePos);
-        //return changed;
     }
 
-    private boolean hoverNodes2(List<IElement> elements, boolean hover, boolean isConnectionTool, Point2D p) {
+    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 {
-            boolean changed = dynamicVisualisationContributionsParticipant.doHover(true, isConnectionTool);
-            if (changed) {
-                // we prefer the first picked element only
-                IElement elem = elements.get(0);
-                G2DParentNode node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
-                if (node instanceof DistrictNetworkVertexNode) {
-                } else {
-                    node = elem.getHint(DistrictNetworkEdgeElement.KEY_DN_EDGE_NODE);
-                }
-                Resource mapElement = elem.getHint(ElementHints.KEY_OBJECT);
-                Resource runtimeDiagram = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);
-                dynamicVisualisationContributionsParticipant.hoverNode(runtimeDiagram, mapElement, node);
-            }
-            return changed;
-        }
-    }
+            dynamicVisualisationContributionsParticipant.doHover(true, isConnectionTool);
 
-    private boolean hoverNodes(List<IElement> elements, boolean hover, boolean isConnectionTool, Point2D p) {
-        boolean changed = false;
-        for (IElement elem : elements) {
-            Node node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
-            if (node instanceof DistrictNetworkVertexNode) {
-                changed |= ((DistrictNetworkVertexNode) node).hover(hover, isConnectionTool);
-                if (hover)
-                    ((DistrictNetworkVertexNode) node).setMousePosition(p);
-            } else {
+            // 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 instanceof DistrictNetworkEdgeNode) {
-                    for (IG2DNode n : ((DistrictNetworkEdgeNode) node).getNodes()) {
-                        if (n instanceof HoverSensitiveNode) {
-                            changed |= ((HoverSensitiveNode)n).hover(hover, isConnectionTool);
-                            if (hover)
-                                ((HoverSensitiveNode)n).setMousePosition(p);
-                        }
-                    }
-                }
-            }
+            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;
         }
-        return changed;
     }
 
-    public boolean isHoveringOverNode(Point2D currentMousePos) {
-        PickRequest req = new PickRequest(currentMousePos).context(getContext());
-        List<IElement> pickables = new ArrayList<IElement>();
+    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);
@@ -146,7 +138,20 @@ public class NetworkDrawingParticipant extends AbstractDiagramParticipant {
         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;
     }
+
 }
index 316370bd2911042683593fb0a1950825517c5859..0ccd12f4152938f5f39a14c931c76e106fb79fbd 100644 (file)
@@ -13,12 +13,10 @@ import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.ToIntFunction;
 
-import org.simantics.district.network.ui.styles.DistrictNetworkHoverInfoStyle;
 import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.NodeException;
 import org.simantics.scenegraph.ParentNode;
 import org.simantics.scenegraph.g2d.G2DNode;
-import org.simantics.scenegraph.g2d.G2DParentNode;
 import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode;
 import org.simantics.scenegraph.profile.common.ProfileVariables;
 import org.simantics.scenegraph.utils.DPIUtil;
@@ -31,6 +29,8 @@ public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensit
 
     private static final long serialVersionUID = 1L;
 
+    private static final String HOVER_INFO_DEFERRED = "hoverInfo";
+
     public static final String NODE_KEY = "DISTRICT_NETWORK_HOVER_INFO";
 
     private static final int PAD = 15;
@@ -51,12 +51,12 @@ public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensit
      */
     private Rectangle2D bgRect = new Rectangle2D.Double();
 
-    private static AtomicReference<G2DParentNode> activeNode = new AtomicReference<>();
+    private static AtomicReference<INode> activeNode = new AtomicReference<>();
 
     @Override
     public void render(Graphics2D g) {
         ParentNode<?> root = (ParentNode<?>) NodeUtil.getNearestParentOfType(this, RTreeNode.class);
-        DeferredRenderingNode deferred = root != null ? (DeferredRenderingNode) root.getNode(DistrictNetworkHoverInfoStyle.HOVER_INFO_DEFERRED) : null;
+        DeferredRenderingNode deferred = root != null ? (DeferredRenderingNode) root.getNode(HOVER_INFO_DEFERRED) : null;
         if (deferred != null)
             deferred.deferNode(g.getTransform(), this);
         else
@@ -198,15 +198,8 @@ public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensit
 
     @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;
     }
 
@@ -221,7 +214,7 @@ public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensit
         activeNode.set(null);
     }
 
-    public void hover2(G2DParentNode hoveredNode) {
+    public void setHoveredNode(INode hoveredNode) {
         ParentNode<?> root = (ParentNode<?>) NodeUtil.getNearestParentOfType(parent, RTreeNode.class);
         if (root != null) {
 
@@ -230,10 +223,10 @@ public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensit
                 throw new NullPointerException("Scenegraph child node was not found: " + "");
             }
 
-            INode existing = NodeUtil.getChildById(child, DistrictNetworkHoverInfoStyle.HOVER_INFO_DEFERRED);
+            INode existing = NodeUtil.getChildById(child, HOVER_INFO_DEFERRED);
             if (existing == null) {
                 if (child instanceof ParentNode<?>) {
-                    existing = ((ParentNode<?>) child).addNode(DistrictNetworkHoverInfoStyle.HOVER_INFO_DEFERRED, DeferredRenderingNode.class);
+                    existing = ((ParentNode<?>) child).addNode(HOVER_INFO_DEFERRED, DeferredRenderingNode.class);
                     ((DeferredRenderingNode)existing).setZIndex(Integer.MAX_VALUE);
                 } else {
                     throw new NodeException("Cannot claim child node for non-parent-node " + child);
index 335f9e118cd1d8c14bd640cc6bd850f6dadb3a18..e54e5308e5a5e094d733c3e317bd04c096d0b7e7 100644 (file)
@@ -30,8 +30,6 @@ import org.simantics.g2d.canvas.Hints;
 import org.simantics.g2d.canvas.ICanvasContext;
 import org.simantics.g2d.canvas.IToolMode;
 import org.simantics.g2d.diagram.IDiagram;
-import org.simantics.maps.elevation.server.SingletonTiffTileInterface;
-import org.simantics.maps.elevation.server.prefs.MapsElevationServerPreferences;
 import org.simantics.scenegraph.g2d.G2DNode;
 import org.simantics.scenegraph.g2d.events.EventTypes;
 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;
@@ -76,7 +74,8 @@ public class NetworkDrawingNode extends G2DNode {
     private static final Color RED_ALPHA = new Color(255, 0, 0, 100);
 
     private boolean scaleStroke = true;
-    
+    private AffineTransform lastViewTransform = new AffineTransform();
+
     @Override
     public void init() {
         super.init();
@@ -96,6 +95,9 @@ public class NetworkDrawingNode extends G2DNode {
 
     @Override
     public void render(Graphics2D g2d) {
+        // Must store this for hover info functionality
+        lastViewTransform = g2d.getTransform();
+
         if (nodes.isEmpty())
             return;
 
@@ -286,7 +288,7 @@ public class NetworkDrawingNode extends G2DNode {
     }
 
     private boolean canStartEdge(Point2D currentPos) {
-        return participant.isHoveringOverNode(currentPos);
+        return participant.isHoveringOverNode(currentPos, lastViewTransform);
     }
 
     private IToolMode getToolMode() {
@@ -300,12 +302,11 @@ public class NetworkDrawingNode extends G2DNode {
         Point2D p = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
         boolean isConnectionTool = mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK);
         // To boost pan perf hovering is only considered if no mouse button is pressed)
-        if (e.buttons == 0 && participant.pickHoveredElement(p, isConnectionTool)) {
+        if (e.buttons == 0 && participant.pickHoveredElement(p, isConnectionTool, lastViewTransform)) {
             repaint = true;
         }
         if (!nodes.isEmpty()) {
             currentMousePos = p;
-            
             repaint();
             return true;
         }
@@ -314,7 +315,7 @@ public class NetworkDrawingNode extends G2DNode {
             repaint();
         return super.mouseMoved(e);
     }
-    
+
     @Override
     protected boolean keyPressed(KeyPressedEvent e) {
         if (e.keyCode == java.awt.event.KeyEvent.VK_ESCAPE) {
@@ -324,6 +325,5 @@ public class NetworkDrawingNode extends G2DNode {
             return true;
         }
         return super.keyPressed(e);
-            
     }
 }
\ No newline at end of file
index 7dd11b7ab83225bcd5e943b42099fffa24df1d1f..9fbb8a29d008f8d24e9c7971b384b04199875ef6 100644 (file)
@@ -3,6 +3,7 @@ package org.simantics.district.network.ui.participants;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Point2D;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ScheduledFuture;
@@ -28,7 +29,7 @@ import org.simantics.district.network.visualisations.model.SizeBarOptions;
 import org.simantics.g2d.canvas.ICanvasContext;
 import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;
 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
-import org.simantics.layer0.Layer0;
+import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.g2d.G2DParentNode;
 import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler;
 import org.simantics.scenegraph.g2d.events.command.CommandEvent;
@@ -54,10 +55,9 @@ public class DynamicVisualisationContributionsParticipant extends AbstractCanvas
             }
         }
     };
-    
+
     private DynamicVisualisationContributionsNode node;
     private AffineTransform transform;
-
     private DistrictNetworkHoverInfoNode hoverInfoNode;
 
     public DynamicVisualisationContributionsParticipant(AffineTransform tr) {
@@ -72,7 +72,7 @@ public class DynamicVisualisationContributionsParticipant extends AbstractCanvas
         getHintStack().addKeyHintListener(getThread(), DistrictDiagramViewer.KEY_MAP_SIZING_OBJECTS, hintListener);
         getHintStack().addKeyHintListener(getThread(), DistrictDiagramViewer.KEY_MAP_SIZE_BAR_OPTIONS, hintListener);
     }
-    
+
     @Override
     public void removedFromContext(ICanvasContext ctx) {
         // Ensure hover polling is stopped
@@ -93,13 +93,13 @@ public class DynamicVisualisationContributionsParticipant extends AbstractCanvas
         node.setTransform(transform);
         node.setEnabled(true);
         node.setZIndex(1000);
-        
+
         hoverInfoNode = parent.addNode("districtNetworkHoverInfoNode", DistrictNetworkHoverInfoNode.class);
         hoverInfoNode.setLookupId("districtNetworkHoverInfoNode");
         hoverInfoNode.setTransform(transform);
         hoverInfoNode.setZIndex(Integer.MAX_VALUE - 500);
     }
-    
+
     @EventHandler(priority = 0)
     protected boolean handleKeyEvent(CommandEvent e) {
         if (e.command.equals(DistrictDiagramViewer.MAP_COLOR_BAR_OPTIONS_CHANGE)) {
@@ -108,20 +108,7 @@ public class DynamicVisualisationContributionsParticipant extends AbstractCanvas
         }
         return false;
     }
-    
-//    @Override
-//    protected boolean handleCommand(CommandEvent e) {
-//        if (e.command.equals(DistrictDiagramViewer.MAP_COLOR_BAR_OPTIONS_CHANGE)) {
-//            ICanvasContext context = (ICanvasContext) e.getContext();
-//            ColorBarOptions options = context.getHintStack().getHint(DistrictDiagramViewer.KEY_MAP_COLOR_BAR_OPTIONS);
-//            this.colorBarsOptions = options;
-//            repaint();
-//            return true;
-//        } else {
-//            return super.handleCommand(e);
-//        }
-//    }
-    
+
     protected void updateNode() {
         node.setDynamicColoringObjects(getDynamicColoringObjects());
         node.setColorBarOptions(getColorBarOptions());
@@ -129,105 +116,102 @@ public class DynamicVisualisationContributionsParticipant extends AbstractCanvas
         node.setSizeBarOptions(getSizeBarOptions());
     }
 
-    private Map<String,DynamicColorContribution> getDynamicColoringObjects() {
-        Map<String,DynamicColorContribution> objects = getHint(DistrictDiagramViewer.KEY_MAP_COLORING_OBJECTS);
-        return objects;
+    private Map<String, DynamicColorContribution> getDynamicColoringObjects() {
+        return getHint(DistrictDiagramViewer.KEY_MAP_COLORING_OBJECTS);
     }
 
     private ColorBarOptions getColorBarOptions() {
-        ColorBarOptions options = getHint(DistrictDiagramViewer.KEY_MAP_COLOR_BAR_OPTIONS);
-        return options;
+        return getHint(DistrictDiagramViewer.KEY_MAP_COLOR_BAR_OPTIONS);
     }
 
     private Map<String, DynamicSizeContribution> getDynamicSizingObjects() {
-        Map<String, DynamicSizeContribution> objects = getHint(DistrictDiagramViewer.KEY_MAP_SIZING_OBJECTS);
-        return objects;
+        return getHint(DistrictDiagramViewer.KEY_MAP_SIZING_OBJECTS);
     }
 
     private SizeBarOptions getSizeBarOptions() {
-        SizeBarOptions options = getHint(DistrictDiagramViewer.KEY_MAP_SIZE_BAR_OPTIONS);
-        return options;
+        return getHint(DistrictDiagramViewer.KEY_MAP_SIZE_BAR_OPTIONS);
     }
 
     private ScheduledFuture<?> hoverUpdateSchedule;
     private static final Object COMPLETE = new Object();
-    
-    public void hoverNode(Resource runtimeDiagram, Resource mapElement, G2DParentNode hoveredNode) {
+
+    public void hoverNode(Resource runtimeDiagram, Resource mapElement, INode hoveredNode, int zoomLevel) {
         IThreadWorkQueue thread = getThread();
         Simantics.getSession().asyncRequest(new ReadRequest() {
-
             @Override
             public void run(ReadGraph graph) throws DatabaseException {
                 DynamicVisualisation visualisation = graph.syncRequest(new RuntimeDynamicVisualisationsRequest(runtimeDiagram));
                 if (visualisation == null)
                     return;
-                if (hoverUpdateSchedule != null && !hoverUpdateSchedule.isDone()) {
-                    hoverUpdateSchedule.cancel(false);
-                }
-                hoverUpdateSchedule = ThreadUtils.getNonBlockingWorkExecutor().scheduleWithFixedDelay(() -> {
-                    
-                    CompletableFuture<Object> future = new CompletableFuture<>();
-                    try {
-                        Simantics.getSession().syncRequest(new ReadRequest() {
-
-                            @Override
-                            public void run(ReadGraph graph) throws DatabaseException {
-                                boolean keyVariablesVertexHover = visualisation.isKeyVariablesVertexHover();
-                                boolean keyVariablesEdgesHover = visualisation.isKeyVariablesEdgesHover();
-
-                                Resource mapElementInstanceOf = graph.getPossibleObject(mapElement, Layer0.getInstance(graph).InstanceOf);
-                                if (mapElementInstanceOf == null) {
-                                    future.complete(COMPLETE);
-                                    return;
-                                }
-
-                                DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
-                                
-                                boolean doHover = true;
-                                if (mapElementInstanceOf.equals(DN.Vertex) && !keyVariablesVertexHover) {
-                                    doHover = false;
-                                } else if (mapElementInstanceOf.equals(DN.Edge) && !keyVariablesEdgesHover) {
-                                    doHover = false;
-                                }
-                                final boolean finalDoHover = doHover;
-                                
-                                StyleResult results = DistrictNetworkHoverInfoStyle.doCalculateStyleResult(graph, runtimeDiagram, mapElement);
-                                if (results != null) {
-                                    Point2D location = DistrictNetworkHoverInfoStyle.calculatePoint(graph, mapElement);
-                                    thread.asyncExec(() -> {
-                                        if (isRemoved())
-                                            return;
-                                        if (finalDoHover) {
-                                            hoverInfoNode.setLabels(results.getLabels());
-                                            hoverInfoNode.setOrigin(results.getOrigin());
-                                            
-                                            hoverInfoNode.setMousePosition(location);
-                                            hoverInfoNode.hover2(hoveredNode);
-                                        } else {
-                                            hoverInfoNode.hover2(null);
-                                        }
-                                        future.complete(COMPLETE);
-                                    });
-                                } else {
-                                    future.complete(COMPLETE);
-                                }
+                cancelCurrentHoverUpdate();
+                hoverUpdateSchedule = ThreadUtils.getNonBlockingWorkExecutor().scheduleWithFixedDelay(
+                        () -> updateHoverInfo(runtimeDiagram, mapElement, hoveredNode, zoomLevel, visualisation, thread),
+                        0,
+                        visualisation.getInterval(),
+                        TimeUnit.MILLISECONDS);
+            }
+        });
+    }
+
+    private void updateHoverInfo(Resource runtimeDiagram, Resource mapElement, INode hoveredNode, int zoomLevel, DynamicVisualisation visualisation, IThreadWorkQueue thread) {
+        CompletableFuture<Object> future = new CompletableFuture<>();
+        try {
+            Simantics.getSession().syncRequest(new ReadRequest() {
+                @Override
+                public void run(ReadGraph graph) throws DatabaseException {
+                    Set<Resource> mapElementTypes = graph.getTypes(mapElement);
+                    if (mapElementTypes.isEmpty()) {
+                        future.complete(COMPLETE);
+                        return;
+                    }
+
+                    DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph);
+
+                    boolean doHover =
+                            (mapElementTypes.contains(DN.Vertex) && visualisation.isKeyVariablesVertexHover())
+                            || (mapElementTypes.contains(DN.Edge) && visualisation.isKeyVariablesEdgesHover());
+
+                    StyleResult results = DistrictNetworkHoverInfoStyle.doCalculateStyleResult(graph, runtimeDiagram, mapElement);
+                    if (results != null) {
+                        Point2D location = DistrictNetworkHoverInfoStyle.calculatePoint(hoveredNode, zoomLevel);
+                        thread.asyncExec(() -> {
+                            if (isRemoved())
+                                return;
+                            if (doHover) {
+                                hoverInfoNode.setLabels(results.getLabels());
+                                hoverInfoNode.setOrigin(results.getOrigin());
+                                hoverInfoNode.setMousePosition(location);
+                                hoverInfoNode.setHoveredNode(hoveredNode);
+                            } else {
+                                hoverInfoNode.setHoveredNode(null);
                             }
+                            future.complete(COMPLETE);
                         });
-                    } catch (DatabaseException e) {
-                        future.completeExceptionally(e);
-                    }
-                    // this waits until everything is done
-                    try {
-                        future.get();
-                    } catch (InterruptedException | ExecutionException e) {
-                        LOGGER.debug("Interrupted hovering", e);
+                    } else {
+                        future.complete(COMPLETE);
                     }
-                }, 0, visualisation.getInterval(), TimeUnit.MILLISECONDS);
-            }
-        });
+                }
+            });
+        } catch (DatabaseException e) {
+            future.completeExceptionally(e);
+        }
+        // this waits until everything is done
+        try {
+            future.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.debug("Interrupted hovering", e);
+        }
     }
 
     public boolean doHover(boolean hover, boolean isConnectionTool) {
+        if (!hover)
+            cancelCurrentHoverUpdate();
         return hoverInfoNode.hover(hover, isConnectionTool);
     }
+
+    private void cancelCurrentHoverUpdate() {
+        if (hoverUpdateSchedule != null && !hoverUpdateSchedule.isDone())
+            hoverUpdateSchedule.cancel(false);
+    }
+
 }
index a5fa89d42b952415f25fb527d2e36c962b32d5ce..ced9b9b50b9f03d4f1f14ae6a5a14614e21340fb 100644 (file)
@@ -1,6 +1,7 @@
 package org.simantics.district.network.ui.styles;
 
 import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 import java.util.Collections;
 import java.util.List;
 
@@ -10,28 +11,21 @@ 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.common.utils.CommonDBUtils;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.exception.MissingVariableException;
 import org.simantics.db.layer0.exception.MissingVariableValueException;
 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.district.network.ui.nodes.DeferredRenderingNode;
-import org.simantics.district.network.ui.nodes.DistrictNetworkHoverInfoNode;
+import org.simantics.district.network.ui.nodes.DistrictNetworkEdgeNode;
 import org.simantics.district.network.ui.nodes.DistrictNetworkNodeUtils;
+import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode;
 import org.simantics.layer0.Layer0;
-import org.simantics.modeling.ModelingResources;
 import org.simantics.scenegraph.INode;
-import org.simantics.scenegraph.ParentNode;
-import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode;
-import org.simantics.scenegraph.profile.EvaluationContext;
-import org.simantics.scenegraph.profile.common.ProfileVariables;
-import org.simantics.scenegraph.utils.NodeUtil;
 import org.simantics.scl.compiler.top.ValueNotFound;
 import org.simantics.scl.osgi.SCLOsgi;
 import org.simantics.scl.runtime.SCLContext;
@@ -41,52 +35,29 @@ import org.simantics.structural.stubs.StructuralResource2;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class DistrictNetworkHoverInfoStyle extends StyleBase<DistrictNetworkHoverInfoStyle.StyleResult> {
-
-    public static final String HOVER_INFO_DEFERRED = "hoverInfo";
-
-       private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkHoverInfoStyle.class);
-
-       private static final String ACTIONS_MODULE = "Actions";
-       private static final String HOVER_CONTRIBUTION = "hoverContribution";
-
-       public static 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 {
-        //return doCalculateStyleResult(graph, runtimeDiagram, mapElement);
-        return new StyleResult(calculatePoint(graph, mapElement), Collections.emptyList());
+public class DistrictNetworkHoverInfoStyle {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DistrictNetworkHoverInfoStyle.class);
+
+    private static final String ACTIONS_MODULE = "Actions";
+    private static final String HOVER_CONTRIBUTION = "hoverContribution";
+
+    public static 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 static StyleResult doCalculateStyleResult(ReadGraph graph, Resource runtimeDiagram, Resource mapElement) throws DatabaseException {
@@ -132,7 +103,7 @@ public class DistrictNetworkHoverInfoStyle extends StyleBase<DistrictNetworkHove
 
         return new StyleResult(point, result);
     }
-    
+
     public static Point2D calculatePoint(ReadGraph graph, Resource mapElement) throws DatabaseException {
         Point2D point;
         DiagramResource DIA = DiagramResource.getInstance(graph);
@@ -153,60 +124,47 @@ public class DistrictNetworkHoverInfoStyle extends StyleBase<DistrictNetworkHove
         return point;
     }
 
-       @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;
-//             
-//             ParentNode<?> root = (ParentNode<?>) NodeUtil.getNearestParentOfType(parent, RTreeNode.class);
-//             if (root != null) {
-//                     DeferredRenderingNode deferred = ProfileVariables.claimChild(root, "", HOVER_INFO_DEFERRED, DeferredRenderingNode.class, observer);
-//                     deferred.setZIndex(Integer.MAX_VALUE);
-//             }
-//             
-//             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);
-                       }
-               }
-       }
+    public static Point2D calculatePoint(INode node, int zoomLevel) {
+        if (node instanceof DistrictNetworkVertexNode) {
+            DistrictNetworkVertexNode vertex = (DistrictNetworkVertexNode) node;
+            Rectangle2D b = vertex.getBounds();
+            return new Point2D.Double(b.getCenterX(), b.getCenterY());
+        } else if (node instanceof DistrictNetworkEdgeNode) {
+            DistrictNetworkEdgeNode edge = (DistrictNetworkEdgeNode) node;
+            return (Point2D) edge.getCenterPoint(zoomLevel).clone();
+        }
+        return null;
+    }
+
+    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 = CommonDBUtils.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);
+            }
+        }
+    }
+
 }