]> gerrit.simantics Code Review - simantics/district.git/blob - 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
1
2 package org.simantics.district.network.ui;
3
4 import java.awt.geom.AffineTransform;
5 import java.awt.geom.Point2D;
6 import java.awt.geom.Rectangle2D;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.Comparator;
10 import java.util.List;
11
12 import org.simantics.db.Resource;
13 import org.simantics.diagram.ui.DiagramModelHints;
14 import org.simantics.district.network.ui.adapters.DistrictNetworkEdgeElement;
15 import org.simantics.district.network.ui.adapters.DistrictNetworkVertexElement;
16 import org.simantics.district.network.ui.nodes.DistrictNetworkVertexNode;
17 import org.simantics.district.network.ui.nodes.NetworkDrawingNode;
18 import org.simantics.district.network.ui.participants.DynamicVisualisationContributionsParticipant;
19 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
20 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
21 import org.simantics.g2d.diagram.IDiagram;
22 import org.simantics.g2d.diagram.handler.PickContext;
23 import org.simantics.g2d.diagram.handler.PickRequest;
24 import org.simantics.g2d.diagram.participant.AbstractDiagramParticipant;
25 import org.simantics.g2d.element.ElementHints;
26 import org.simantics.g2d.element.IElement;
27 import org.simantics.maps.MapScalingTransform;
28 import org.simantics.scenegraph.INode;
29 import org.simantics.scenegraph.Node;
30 import org.simantics.scenegraph.g2d.G2DParentNode;
31 import org.simantics.scenegraph.utils.GeometryUtils;
32
33 public class NetworkDrawingParticipant extends AbstractDiagramParticipant {
34
35     public static final String NETWORK_DRAWING_NODE = "networkDrawingNode";
36
37     @Dependency
38     PickContext pick;
39
40     private NetworkDrawingNode node;
41     private DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant;
42     private AffineTransform transform;
43
44     /**
45      * Holds the current element for which hover information is shown.
46      * This is just to optimize the 
47      */
48     private IElement currentHoverElement;
49
50     public NetworkDrawingParticipant(DynamicVisualisationContributionsParticipant dynamicVisualisationContributionsParticipant, AffineTransform transform) {
51         this.dynamicVisualisationContributionsParticipant = dynamicVisualisationContributionsParticipant;
52         this.transform = transform;
53     }
54
55     @SGInit
56     public void initSG(G2DParentNode parent) {
57         node = parent.addNode(NETWORK_DRAWING_NODE, NetworkDrawingNode.class);
58         node.setTransform(transform);
59         node.setNetworkDrawingParticipant(this);
60     }
61
62     @Override
63     protected void onDiagramSet(IDiagram newDiagram, IDiagram oldDiagram) {
64         node.setDiagram(newDiagram);
65     }
66
67     public boolean pickHoveredElement(Point2D canvasPos, boolean isConnectionTool, AffineTransform viewTransform) {
68         PickRequest req = new PickRequest(getPickRect(canvasPos, viewTransform)).context(getContext());
69         List<IElement> pickables = new ArrayList<>();
70         pick.pick(diagram, req, pickables);
71         
72
73         Comparator<IElement> nearestVerticesFirst = (IElement e1, IElement e2) -> {
74             // If there are any vertices in the elements, prefer those primarily.
75             DistrictNetworkVertexNode v1 = e1.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
76             DistrictNetworkVertexNode v2 = e2.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
77
78             // Don't reorder edges
79             if ((v1 == null && v2 == null))
80                 return 0;
81
82             // Sort vertices in nearest first order
83             if (v1 != null && v2 != null) {
84                 Rectangle2D b1 = v1.getBounds();
85                 Rectangle2D b2 = v2.getBounds();
86                 double dist1 = canvasPos.distanceSq(b1.getCenterX(), b1.getCenterY());
87                 double dist2 = canvasPos.distanceSq(b2.getCenterX(), b2.getCenterY());
88                 return dist1 < dist2 ? -1 : dist1 > dist2 ? 1 : 0;
89             }
90
91             // Always vertices before edges
92             return v1 != null && v2 == null ? -1 : 1;
93         };
94
95         Collections.sort(pickables, nearestVerticesFirst);
96
97         updateHoveredElement(pickables, true, isConnectionTool, viewTransform);
98         // Will repaint once the async hover info calculation is ready, no need to do it here
99         return false;
100     }
101
102     private boolean updateHoveredElement(List<IElement> elements, boolean hover, boolean isConnectionTool, AffineTransform viewTransform) {
103         if (elements == null || elements.isEmpty()) {
104             currentHoverElement = null;
105             return dynamicVisualisationContributionsParticipant.doHover(false, isConnectionTool);
106         } else {
107             dynamicVisualisationContributionsParticipant.doHover(true, isConnectionTool);
108
109             // we prefer the first picked element only
110             IElement elem = elements.get(0);
111             if (elem.equals(currentHoverElement))
112                 return false;
113
114             INode node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
115             if (node == null)
116                 node = elem.getHint(DistrictNetworkEdgeElement.KEY_DN_EDGE_NODE);
117             if (node == null)
118                 return false;
119
120             Resource mapElement = elem.getHint(ElementHints.KEY_OBJECT);
121             Resource runtimeDiagram = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);
122             currentHoverElement = elem;
123             dynamicVisualisationContributionsParticipant.hoverNode(runtimeDiagram, mapElement, node, MapScalingTransform.zoomLevel(viewTransform));
124             return true;
125         }
126     }
127
128     public boolean isHoveringOverNode(Point2D canvasPos, AffineTransform viewTransform) {
129         PickRequest req = new PickRequest(getPickRect(canvasPos, viewTransform)).context(getContext());
130         List<IElement> pickables = new ArrayList<>();
131         pick.pick(diagram, req, pickables);
132         for (IElement elem : pickables) {
133             Node node = elem.getHint(DistrictNetworkVertexElement.KEY_DN_VERTEX_NODE);
134             if (node instanceof DistrictNetworkVertexNode) {
135                 return true;
136             }
137         }
138         return false;
139     }
140
141     private Rectangle2D getPickRect(Point2D canvasPos, AffineTransform viewTransform) {
142         double pixelScale = 1.0 / GeometryUtils.getScale(viewTransform);
143         if (Double.isInfinite(pixelScale))
144             pixelScale = 1e-8;
145
146         Rectangle2D pickRect = GeometryUtils.expandRectangle(
147                 new Rectangle2D.Double(canvasPos.getX(), canvasPos.getY(), 0, 0),
148                 pixelScale * 4);
149
150         return pickRect;
151     }
152
153     public AffineTransform getTransform() {
154         return transform;
155     }
156
157 }