1 package org.simantics.district.network.ui.nodes;
5 import java.awt.Graphics2D;
6 import java.awt.geom.AffineTransform;
7 import java.awt.geom.Point2D;
8 import java.awt.geom.Rectangle2D;
9 import java.util.Comparator;
10 import java.util.List;
11 import java.util.Optional;
12 import java.util.concurrent.atomic.AtomicReference;
14 import org.simantics.district.network.ui.styles.DistrictNetworkHoverInfoStyle;
15 import org.simantics.maps.MapScalingTransform;
16 import org.simantics.scenegraph.INode;
17 import org.simantics.scenegraph.NodeException;
18 import org.simantics.scenegraph.ParentNode;
19 import org.simantics.scenegraph.g2d.G2DNode;
20 import org.simantics.scenegraph.g2d.G2DParentNode;
21 import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode;
22 import org.simantics.scenegraph.profile.common.ProfileVariables;
23 import org.simantics.scenegraph.utils.DPIUtil;
24 import org.simantics.scenegraph.utils.NodeUtil;
25 import org.simantics.scl.runtime.Lists;
26 import org.simantics.scl.runtime.tuple.Tuple3;
28 public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensitiveNode, DeferredNode {
30 private static final Font FONT = new Font("Tahoma", Font.PLAIN, (int)(DPIUtil.upscale(9) * MapScalingTransform.getScaleY() + 0.5));
32 private static final long serialVersionUID = 1L;
34 public static final String NODE_KEY = "DISTRICT_NETWORK_HOVER_INFO";
36 private static final int W1 = 50;
37 private static final int W2 = 30;
38 private static final int PAD = 5;
40 private List<Tuple3> labels;
42 @SuppressWarnings("unused")
43 private Point2D origin;
45 private boolean hover = false;
47 private Point2D mousePosition;
49 private static AtomicReference<G2DParentNode> activeNode = new AtomicReference<>();
52 public void render(Graphics2D g) {
54 ParentNode<?> root = (ParentNode<?>) NodeUtil.getNearestParentOfType(this, RTreeNode.class);
55 DeferredRenderingNode deferred = root != null ? (DeferredRenderingNode) root.getNode(DistrictNetworkHoverInfoStyle.HOVER_INFO_DEFERRED) : null;
57 deferred.deferNode(g.getTransform(), this);
63 public void renderDeferred(Graphics2D g) {
64 if (!hover || activeNode.get() == null)
66 AffineTransform ot = g.getTransform();
67 Font of = g.getFont();
73 private void doRender(Graphics2D g) {
74 AffineTransform tt = getTransform();
76 if (mousePosition == null)
78 g.translate(mousePosition.getX(), mousePosition.getY());
79 //g.translate(origin.getX(), origin.getY());
80 double scale = 1.5 / g.getTransform().getScaleX();
81 g.scale(scale, scale);
84 double rowHeight = g.getFontMetrics().getHeight() * 1.1;
86 // let's calculate the max width
87 Optional<Integer> max = labels.stream().map(t -> g.getFontMetrics().stringWidth((String) t.c2)).max(Comparator.naturalOrder());
88 int width = max.orElse(10);
89 g.setColor(Color.WHITE);
90 int totalHeight = (int)Math.round(rowHeight * labels.size());
91 g.fillRect(-(W1 + PAD + W2 + 5), -(totalHeight + (int)Math.round(rowHeight)), (W1 + PAD + W2 + width + 10), totalHeight + 5);
93 g.setColor(Color.BLACK);
95 for (Tuple3 t : labels) {
96 g.translate(0.f, -rowHeight);
99 g.drawString((String) t.c0, -(W1 + PAD + W2), 0.f);
103 int width1 = g.getFontMetrics().stringWidth((String) t.c1);
104 g.drawString((String) t.c1, - width1, 0.f);
108 g.drawString((String) t.c2, PAD, 0.f);
114 public Rectangle2D getBoundsInLocal() {
118 @SuppressWarnings("unchecked")
119 public void setLabels(List<Tuple3> list) {
120 this.labels = Lists.reverse(list);
123 public void setOrigin(Point2D origin) {
124 this.origin = origin;
128 public boolean hover(boolean hover, boolean isConnectionTool) {
129 // hover = hover && activeNode.updateAndGet(current -> current == null ? this : current) == this;
130 boolean changed = hover != this.hover;
134 // if (!hover) activeNode.updateAndGet(current -> current == this ? null : current);
142 public void setMousePosition(Point2D p) {
147 public void delete() {
149 activeNode.set(null);
152 public void hover2(G2DParentNode hoveredNode) {
153 ParentNode<?> root = (ParentNode<?>) NodeUtil.getNearestParentOfType(parent, RTreeNode.class);
156 INode child = ProfileVariables.browseChild(root, "");
158 throw new NullPointerException("Scenegraph child node was not found: " + "");
161 INode existing = NodeUtil.getChildById(child, DistrictNetworkHoverInfoStyle.HOVER_INFO_DEFERRED);
162 if (existing == null) {
163 if (child instanceof ParentNode<?>) {
164 existing = ((ParentNode<?>) child).addNode(DistrictNetworkHoverInfoStyle.HOVER_INFO_DEFERRED, DeferredRenderingNode.class);
165 ((DeferredRenderingNode)existing).setZIndex(Integer.MAX_VALUE);
167 throw new NodeException("Cannot claim child node for non-parent-node " + child);
172 activeNode.set(hoveredNode);