]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/DistrictNetworkHoverInfoNode.java
Adjustments to map diagram info label rendering
[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.ParentNode;
17 import org.simantics.scenegraph.g2d.G2DNode;
18 import org.simantics.scenegraph.g2d.nodes.spatial.RTreeNode;
19 import org.simantics.scenegraph.utils.DPIUtil;
20 import org.simantics.scenegraph.utils.NodeUtil;
21 import org.simantics.scl.runtime.Lists;
22 import org.simantics.scl.runtime.tuple.Tuple3;
23
24 public class DistrictNetworkHoverInfoNode extends G2DNode implements HoverSensitiveNode, DeferredNode {
25
26         private static final Font FONT = new Font("Tahoma", Font.PLAIN, (int)(DPIUtil.upscale(9) * MapScalingTransform.getScaleY() + 0.5));
27
28         private static final long serialVersionUID = 1L;
29
30         public static final String NODE_KEY = "DISTRICT_NETWORK_HOVER_INFO";
31
32         private static final int W1 = 50;
33         private static final int W2 = 30;
34         private static final int PAD = 5;
35
36         private List<Tuple3> labels;
37
38         @SuppressWarnings("unused")
39         private Point2D origin;
40
41         private boolean hover = false;
42
43         private Point2D mousePosition;
44         
45         private static AtomicReference<DistrictNetworkHoverInfoNode> activeNode = new AtomicReference<>();
46
47         @Override
48         public void render(Graphics2D g) {
49                 if (!hover || activeNode.get() != this)
50                         return;
51
52                 ParentNode<?> root = (ParentNode<?>) NodeUtil.getNearestParentOfType(this, RTreeNode.class);
53                 DeferredRenderingNode deferred = root != null ? (DeferredRenderingNode) root.getNode(DistrictNetworkHoverInfoStyle.HOVER_INFO_DEFERRED) : null;
54                 if (deferred != null)
55                         deferred.deferNode(g.getTransform(), this);
56                 else
57                         renderDeferred(g);
58         }
59         
60         @Override
61         public void renderDeferred(Graphics2D g) {
62                 AffineTransform ot = g.getTransform();
63                 Font of = g.getFont();
64                 doRender(g);
65                 g.setFont(of);
66                 g.setTransform(ot);
67         }
68
69         private void doRender(Graphics2D g) {
70                 g.transform(MapScalingTransform.INVERSE);
71                 g.translate(mousePosition.getX(), mousePosition.getY());
72                 //g.translate(origin.getX(), origin.getY());
73                 double scale = 1.5 / g.getTransform().getScaleX();
74                 g.scale(scale, scale);
75
76                 g.setFont(FONT);
77                 double rowHeight = g.getFontMetrics().getHeight() * 1.1;
78
79         // let's calculate the max width
80         Optional<Integer> max = labels.stream().map(t -> g.getFontMetrics().stringWidth((String) t.c2)).max(Comparator.naturalOrder());
81         int width = max.orElse(10);
82         g.setColor(Color.WHITE);
83         int totalHeight = (int)Math.round(rowHeight * labels.size());
84         g.fillRect(-(W1 + PAD + W2 + 5), -(totalHeight + (int)Math.round(rowHeight)), (W1 + PAD + W2 + width + 10), totalHeight + 5);
85
86                 g.setColor(Color.BLACK);
87                 
88                 for (Tuple3 t : labels) {
89                         g.translate(0.f, -rowHeight);
90                         
91                         if (t.c0 != null) {
92                                 g.drawString((String) t.c0, -(W1 + PAD + W2), 0.f);
93                         }
94                         
95                         if (t.c1 != null) {
96                                 int width1 = g.getFontMetrics().stringWidth((String) t.c1);
97                                 g.drawString((String) t.c1, - width1, 0.f);
98                         }
99                         
100                         if (t.c2 != null) {
101                                 g.drawString((String) t.c2, PAD, 0.f);
102                         }
103                 }
104         }
105
106         @Override
107         public Rectangle2D getBoundsInLocal() {
108                 return null;
109         }
110
111         @SuppressWarnings("unchecked")
112         public void setLabels(List<Tuple3> list) {
113                 this.labels = Lists.reverse(list);
114         }
115
116         public void setOrigin(Point2D origin) {
117                 this.origin = origin;
118         }
119
120         @Override
121         public boolean hover(boolean hover, boolean isConnectionTool) {
122                 hover = hover && activeNode.updateAndGet(current -> current == null ? this : current) == this;
123                 boolean changed = hover != this.hover;
124                 this.hover = hover;
125                 
126                 if (changed) {
127                         if (!hover) activeNode.updateAndGet(current -> current == this ? null : current);
128                         repaint();
129                 }
130                 
131                 return changed;
132         }
133         
134         @Override
135         public void setMousePosition(Point2D p) {
136                 mousePosition = p;
137         }
138         
139         @Override
140         public void delete() {
141                 super.delete();
142                 activeNode.getAndUpdate(current -> current == this ? null : current);
143         }
144 }