From: Tuukka Lehtonen Date: Fri, 29 Nov 2019 14:04:42 +0000 (+0200) Subject: Usability fixes for district network node hover info showing X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fdistrict.git;a=commitdiff_plain;h=86d471d96d6bc11bf7629113e57c6d9a9916e608 Usability fixes for district network node hover info showing 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: Ie20ae4831effcd1d4a78f0cdf45fd3fbc2c14993 --- diff --git a/org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph b/org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph index d17219de..56488bfa 100644 --- a/org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph +++ b/org.simantics.district.network.ontology/graph/DistrictNetworkProfiles.pgraph @@ -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 diff --git a/org.simantics.district.network.ui/adapters.xml b/org.simantics.district.network.ui/adapters.xml index f4dea68a..16993605 100644 --- a/org.simantics.district.network.ui/adapters.xml +++ b/org.simantics.district.network.ui/adapters.xml @@ -23,10 +23,6 @@ - - - diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java index 77ec735f..e5ce207e 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/NetworkDrawingParticipant.java @@ -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 pickables = new ArrayList<>(); pick.pick(diagram, req, pickables); + + + Comparator 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 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 elements, boolean hover, boolean isConnectionTool, Point2D p) { + private boolean updateHoveredElement(List 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 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 pickables = new ArrayList(); + public boolean isHoveringOverNode(Point2D canvasPos, AffineTransform viewTransform) { + PickRequest req = new PickRequest(getPickRect(canvasPos, viewTransform)).context(getContext()); + List 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; } + } 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 index 316370bd..0ccd12f4 100644 --- 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 @@ -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 activeNode = new AtomicReference<>(); + private static AtomicReference 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); diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java index 335f9e11..e54e5308 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java @@ -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 diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DynamicVisualisationContributionsParticipant.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DynamicVisualisationContributionsParticipant.java index 7dd11b7a..9fbb8a29 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DynamicVisualisationContributionsParticipant.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/participants/DynamicVisualisationContributionsParticipant.java @@ -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 getDynamicColoringObjects() { - Map objects = getHint(DistrictDiagramViewer.KEY_MAP_COLORING_OBJECTS); - return objects; + private Map 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 getDynamicSizingObjects() { - Map 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 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 future = new CompletableFuture<>(); + try { + Simantics.getSession().syncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + Set 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); + } + } diff --git a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/styles/DistrictNetworkHoverInfoStyle.java b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/styles/DistrictNetworkHoverInfoStyle.java index 4dac92c1..bdb0b731 100644 --- a/org.simantics.district.network.ui/src/org/simantics/district/network/ui/styles/DistrictNetworkHoverInfoStyle.java +++ b/org.simantics.district.network.ui/src/org/simantics/district/network/ui/styles/DistrictNetworkHoverInfoStyle.java @@ -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; @@ -17,21 +18,14 @@ 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 { - - 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 labels; - - public StyleResult(Point2D origin, List labels) { - this.origin = origin; - this.labels = labels; - } - - public Point2D getOrigin() { - return origin; - } - - public List getLabels() { - return labels; - } - } - - public DistrictNetworkHoverInfoStyle(Resource style) throws DatabaseException { - super(); - } - - 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 labels; + + public StyleResult(Point2D origin, List labels) { + this.origin = origin; + this.labels = labels; + } + + public Point2D getOrigin() { + return origin; + } + + public List getLabels() { + return labels; + } } public static StyleResult doCalculateStyleResult(ReadGraph graph, Resource runtimeDiagram, Resource mapElement) throws DatabaseException { @@ -132,7 +103,7 @@ public class DistrictNetworkHoverInfoStyle extends StyleBase 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> getUCTextGridFunctionCached(ReadGraph graph, Resource componentType) - throws DatabaseException { - return graph.syncRequest(new UCTextGridFunctionRequest(componentType), TransientCacheListener.instance()); - } - - private static final class UCTextGridFunctionRequest extends ResourceRead>> { - public UCTextGridFunctionRequest(Resource resource) { - super(resource); - } - - @SuppressWarnings("unchecked") - @Override - public Function1> 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>) 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> getUCTextGridFunctionCached(ReadGraph graph, Resource componentType) + throws DatabaseException { + return graph.syncRequest(new UCTextGridFunctionRequest(componentType), TransientCacheListener.instance()); + } + + private static final class UCTextGridFunctionRequest extends ResourceRead>> { + public UCTextGridFunctionRequest(Resource resource) { + super(resource); + } + + @SuppressWarnings("unchecked") + @Override + public Function1> 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>) SCLOsgi.MODULE_REPOSITORY.getValue(uri, HOVER_CONTRIBUTION); + } catch (ValueNotFound e1) { + return null; + } finally { + sclContext.put("graph", oldGraph); + } + } + } + }