]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoNode.java
07ad2eedb4df1decd66f4ac0e965a76a67d6039c
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / nodes / DistrictNetworkHoverInfoNode.java
1 package org.simantics.district.network.ui.nodes;
2
3 import java.awt.Color;
4 import java.awt.Font;
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;
13
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;
27
28 public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensitiveNode, DeferredNode {
29
30         private static final Font FONT = new Font("Tahoma", Font.PLAIN, (int)(DPIUtil.upscale(9) * MapScalingTransform.getScaleY() + 0.5));
31
32         private static final long serialVersionUID = 1L;
33
34         public static final String NODE_KEY = "DISTRICT_NETWORK_HOVER_INFO";
35
36         private static final int W1 = 50;
37         private static final int W2 = 30;
38         private static final int PAD = 5;
39
40         private List<Tuple3> labels;
41
42         @SuppressWarnings("unused")
43         private Point2D origin;
44
45         private boolean hover = false;
46
47         private Point2D mousePosition;
48         
49         private static AtomicReference<G2DParentNode> activeNode = new AtomicReference<>();
50
51         @Override
52         public void render(Graphics2D g) {
53
54                 ParentNode<?> root = (ParentNode<?>) NodeUtil.getNearestParentOfType(this, RTreeNode.class);
55                 DeferredRenderingNode deferred = root != null ? (DeferredRenderingNode) root.getNode(DistrictNetworkHoverInfoStyle.HOVER_INFO_DEFERRED) : null;
56                 if (deferred != null)
57                         deferred.deferNode(g.getTransform(), this);
58                 else
59                         renderDeferred(g);
60         }
61         
62         @Override
63         public void renderDeferred(Graphics2D g) {
64             if (!hover || activeNode.get() == null)
65                 return;
66                 AffineTransform ot = g.getTransform();
67                 Font of = g.getFont();
68                 doRender(g);
69                 g.setFont(of);
70                 g.setTransform(ot);
71         }
72
73         private void doRender(Graphics2D g) {
74             AffineTransform tt = getTransform();
75                 g.transform(tt);
76                 if (mousePosition == null)
77                     return;
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);
82
83                 g.setFont(FONT);
84                 double rowHeight = g.getFontMetrics().getHeight() * 1.1;
85
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);
92
93                 g.setColor(Color.BLACK);
94                 
95                 for (Tuple3 t : labels) {
96                         g.translate(0.f, -rowHeight);
97                         
98                         if (t.c0 != null) {
99                                 g.drawString((String) t.c0, -(W1 + PAD + W2), 0.f);
100                         }
101                         
102                         if (t.c1 != null) {
103                                 int width1 = g.getFontMetrics().stringWidth((String) t.c1);
104                                 g.drawString((String) t.c1, - width1, 0.f);
105                         }
106                         
107                         if (t.c2 != null) {
108                                 g.drawString((String) t.c2, PAD, 0.f);
109                         }
110                 }
111         }
112
113         @Override
114         public Rectangle2D getBoundsInLocal() {
115                 return null;
116         }
117
118         @SuppressWarnings("unchecked")
119         public void setLabels(List<Tuple3> list) {
120                 this.labels = Lists.reverse(list);
121         }
122
123         public void setOrigin(Point2D origin) {
124                 this.origin = origin;
125         }
126
127         @Override
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;
131                 this.hover = hover;
132 //              
133 //              if (changed) {
134 //                      if (!hover) activeNode.updateAndGet(current -> current == this ? null : current);
135 //                      repaint();
136 //              }
137 //              
138                 return changed;
139         }
140         
141         @Override
142         public void setMousePosition(Point2D p) {
143                 mousePosition = p;
144         }
145         
146         @Override
147         public void delete() {
148                 super.delete();
149                 activeNode.set(null);
150         }
151
152     public void hover2(G2DParentNode hoveredNode) {
153         ParentNode<?> root = (ParentNode<?>) NodeUtil.getNearestParentOfType(parent, RTreeNode.class);
154         if (root != null) {
155             
156             INode child = ProfileVariables.browseChild(root, "");
157             if(child == null) {
158                 throw new NullPointerException("Scenegraph child node was not found: " + "");
159             }
160
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);
166                 } else {
167                     throw new NodeException("Cannot claim child node for non-parent-node " + child);
168                 }
169             }
170         }
171
172         activeNode.set(hoveredNode);
173         repaint();
174     }
175
176 }