-\r
-package org.simantics.district.network.ui;\r
-\r
-import org.simantics.district.network.ui.nodes.NetworkDrawingNode;\r
-import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;\r
-import org.simantics.g2d.diagram.IDiagram;\r
-import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;\r
-import org.simantics.scenegraph.g2d.G2DParentNode;\r
-import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
-import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
-\r
-public class NetworkDrawingParticipant extends AbstractDiagramParticipant {\r
-\r
- /**\r
- * A hint key for terminal pick distance in control pixels.\r
- * @see #PICK_DIST\r
- */\r
- public static final Key KEY_PICK_DISTANCE = new KeyOf(Double.class, "PICK_DISTANCE");\r
-\r
- /**\r
- * Default terminal pick distance in control pixels.\r
- * @see #DEFAULT_PICK_DISTANCE\r
- */\r
- public static final double PICK_DIST = 10;\r
- \r
- private NetworkDrawingNode node;\r
- \r
- @SGInit\r
- public void initSG(G2DParentNode parent) {\r
- node = parent.addNode("networkDrawingNode", NetworkDrawingNode.class);\r
- node.setNetworkDrawingParticipant(this);\r
- }\r
- \r
- @Override\r
- protected void onDiagramSet(IDiagram newDiagram, IDiagram oldDiagram) {\r
- node.setDiagram(newDiagram);\r
- }\r
-\r
-}\r
+
+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.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.DNPickSorter;
+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.scenegraph.utils.GeometryUtils;
+
+public class NetworkDrawingParticipant extends AbstractDiagramParticipant {
+
+ public static final String NETWORK_DRAWING_NODE = "networkDrawingNode";
+
+ @Dependency
+ PickContext pick;
+
+ private NetworkDrawingNode node;
+ private DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant;
+ private AffineTransform transform;
+
+ /**
+ * Holds the current element for which hover information is shown.
+ * This exists only to optimize the hover updating procedure.
+ */
+ private IElement currentHoverElement;
+
+ public NetworkDrawingParticipant(DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant, AffineTransform transform) {
+ this.dynamicVisualisationContributionsParticipant = dynamicVisualisationContributionsParticipant;
+ this.transform = transform;
+ }
+
+ @SGInit
+ public void initSG(G2DParentNode parent) {
+ 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 canvasPos, boolean isConnectionTool, AffineTransform viewTransform) {
+ PickRequest req = new PickRequest(getPickRect(canvasPos, viewTransform)).context(getContext());
+ List<IElement> pickables = new ArrayList<>();
+ pick.pick(diagram, req, pickables);
+
+ Collections.sort(pickables, DNPickSorter.nearestVerticesFirst(false, DNPickSorter.centerDistSq(canvasPos.getX(), canvasPos.getY())));
+
+ 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) {
+ return true;
+ }
+ }
+ 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;
+ }
+
+}