]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.district.network.ui/src/org/simantics/district/network/ui/nodes/NetworkDrawingNode.java
Fixed regressions in box selection and element color function validation
[simantics/district.git] / org.simantics.district.network.ui / src / org / simantics / district / network / ui / nodes / NetworkDrawingNode.java
1 package org.simantics.district.network.ui.nodes;
2
3 import java.awt.BasicStroke;
4 import java.awt.Color;
5 import java.awt.Graphics2D;
6 import java.awt.Stroke;
7 import java.awt.geom.Path2D;
8 import java.awt.geom.Point2D;
9 import java.awt.geom.Rectangle2D;
10 import java.util.ArrayList;
11 import java.util.Iterator;
12 import java.util.List;
13
14 import org.simantics.Simantics;
15 import org.simantics.db.Resource;
16 import org.simantics.db.WriteGraph;
17 import org.simantics.db.common.request.WriteRequest;
18 import org.simantics.db.exception.DatabaseException;
19 import org.simantics.diagram.ui.DiagramModelHints;
20 import org.simantics.district.network.ModelledCRS;
21 import org.simantics.district.network.ui.DNEdgeBuilder;
22 import org.simantics.district.network.ui.NetworkDrawingParticipant;
23 import org.simantics.g2d.canvas.Hints;
24 import org.simantics.g2d.canvas.IToolMode;
25 import org.simantics.g2d.diagram.IDiagram;
26 import org.simantics.scenegraph.g2d.G2DNode;
27 import org.simantics.scenegraph.g2d.events.EventTypes;
28 import org.simantics.scenegraph.g2d.events.KeyEvent.KeyPressedEvent;
29 import org.simantics.scenegraph.g2d.events.MouseEvent;
30 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseClickEvent;
31 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDoubleClickedEvent;
32 import org.simantics.scenegraph.g2d.events.MouseEvent.MouseMovedEvent;
33 import org.simantics.scenegraph.utils.GeometryUtils;
34 import org.simantics.scenegraph.utils.NodeUtil;
35
36 public class NetworkDrawingNode extends G2DNode {
37
38     private static final long serialVersionUID = -3475301184009620573L;
39     
40     private Point2D currentMousePos = null;
41     
42     private List<Point2D> nodes = new ArrayList<>();
43
44     private Resource diagramResource;
45
46     private boolean committed;
47
48     private NetworkDrawingParticipant participant;
49
50     private IDiagram diagram;
51
52     private static final Stroke DASHED_STROKE = new BasicStroke(2.0f,
53             BasicStroke.CAP_ROUND,
54             BasicStroke.JOIN_ROUND,
55             4.0f, new float[]{4.0f}, 0.0f);
56
57     private static final Color BLUE_ALPHA = new Color(0, 0, 255, 100);
58
59     private boolean scaleStroke = true;
60     
61     @Override
62     public void init() {
63         super.init();
64         addEventHandler(this);
65     }
66     
67     public void setNetworkDrawingParticipant(NetworkDrawingParticipant participant) {
68         this.participant = participant;
69     }
70     
71     public void setDiagram(IDiagram diagram) {
72         if (diagram != null) {
73             this.diagram = diagram;
74             this.diagramResource = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RESOURCE);
75         }
76     }
77
78     @Override
79     public void render(Graphics2D g2d) {
80         if (nodes.isEmpty())
81             return;
82         
83         Path2D path = new Path2D.Double();
84         Iterator<Point2D> nodeIter = nodes.iterator();
85         if (nodeIter.hasNext()) {
86             Point2D node = nodeIter.next();
87             path.moveTo(node.getX(), node.getY());
88         }
89         while (nodeIter.hasNext()) {
90             Point2D node = nodeIter.next();
91             path.lineTo(node.getX(), node.getY());
92         }
93         if (currentMousePos != null)
94             path.lineTo(currentMousePos.getX(), currentMousePos.getY());
95         
96         Color old = g2d.getColor();
97         Stroke oldStroke = g2d.getStroke();
98         
99         if (DASHED_STROKE != null) {
100             if (scaleStroke && DASHED_STROKE instanceof BasicStroke) {
101                 BasicStroke bs = GeometryUtils.scaleStroke(DASHED_STROKE, (float) (1.0 / GeometryUtils.getScale(g2d.getTransform())));
102                 g2d.setStroke(bs);
103             } else {
104                 g2d.setStroke(DASHED_STROKE);
105             }
106         }
107         
108         g2d.setColor(BLUE_ALPHA);
109
110         g2d.draw(path);
111         
112         g2d.setStroke(oldStroke);
113         g2d.setColor(old);
114     }
115
116     @Override
117     public Rectangle2D getBoundsInLocal() {
118         return null;
119     }
120     
121     @Override
122     public int getEventMask() {
123         return EventTypes.AnyMask;
124     }
125     
126     @Override
127     protected boolean mouseDoubleClicked(MouseDoubleClickedEvent e) {
128         // nodes to path2d
129         IToolMode mode = getToolMode();
130         if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
131             Point2D start = null;
132             Point2D end = null;
133             Iterator<Point2D> nodeIter = nodes.iterator();
134             while (nodeIter.hasNext()) {
135                 if (end == null) {
136                     start = nodeIter.next();
137                     if (!nodeIter.hasNext()) {
138                         break;
139                     }
140                 } else {
141                     start = end;
142                 }
143                 
144                 end = nodeIter.next();
145                 
146                 createEdge(start, end);
147             }
148             
149             nodes.clear();
150             committed = true;
151             
152             repaint();
153             
154             return true;
155         }
156         return super.mouseDoubleClicked(e);
157     }
158
159     private void createEdge(Point2D start, Point2D end) {
160         
161         double padding = GeometryUtils.getScale(getTransform());
162         
163         /*
164          *  To convert y-coordinates to map coordinates in ruler, use:
165          *    double val = (y-offsetY)/scaleY;
166          *    val = Math.toDegrees(Math.atan(Math.sinh(Math.toRadians(val))));
167          *    String str = formatValue(val);
168          */
169         // TODO: fix scale
170         double scaleY = getTransform().getScaleY();
171         double scaleX = getTransform().getScaleX();
172         
173         double startLat = ModelledCRS.yToLatitude(-start.getY() / scaleY);
174         double startLon = ModelledCRS.xToLongitude(start.getX() / scaleX);
175         
176         double endLat = ModelledCRS.yToLatitude(-end.getY() / scaleY);
177         double endLon = ModelledCRS.xToLongitude(end.getX() / scaleX);
178         
179         double[] startCoords = new double[] { startLon, startLat };
180         double[] endCoords = new double[] { endLon, endLat };
181         
182         DNEdgeBuilder builder = new DNEdgeBuilder(diagramResource, diagram);
183         Simantics.getSession().asyncRequest(new WriteRequest() {
184             
185             @Override
186             public void perform(WriteGraph graph) throws DatabaseException {
187                 builder.create(graph, startCoords, endCoords, 1 / padding);
188             }
189         });
190         
191     }
192
193     @Override
194     protected boolean mouseClicked(MouseClickEvent e) {
195         // check ToolMode
196         IToolMode mode = getToolMode();
197         if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
198             if (committed) {
199                 committed = false;
200                 return false;
201             }
202             if (e.button == MouseEvent.RIGHT_BUTTON && !nodes.isEmpty()) {
203                 nodes.remove(nodes.size() - 1);
204             } else if (e.button == MouseEvent.LEFT_BUTTON) {
205                 Point2D localPos = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
206                 nodes.add(new Point2D.Double(localPos.getX(), localPos.getY()));
207             }
208             repaint();
209             return true;
210         }
211         return super.mouseClicked(e);
212     }
213     
214     private IToolMode getToolMode() {
215         return participant.getHint(Hints.KEY_TOOL);
216     }
217
218     @Override
219     protected boolean mouseMoved(MouseMovedEvent e) {
220         IToolMode mode = getToolMode();
221         if (mode == Hints.CONNECTTOOL || e.hasAnyModifier(MouseEvent.ALT_MASK | MouseEvent.ALT_GRAPH_MASK)) {
222             boolean repaint = false;
223             Point2D p = NodeUtil.worldToLocal(this, e.controlPosition, new Point2D.Double());
224             if (participant.pickHoveredElement(p)) {
225                 repaint = true;
226             }
227             if (!nodes.isEmpty()) {
228                 currentMousePos = p;
229                 
230                 repaint();
231                 return true;
232             }
233             currentMousePos = null;
234             if (repaint == true)
235                 repaint();
236         }
237         return super.mouseMoved(e);
238     }
239     
240     @Override
241     protected boolean keyPressed(KeyPressedEvent e) {
242         if (e.keyCode == java.awt.event.KeyEvent.VK_ESCAPE) {
243             nodes.clear();
244             repaint();
245             return true;
246         }
247         return super.keyPressed(e);
248             
249     }
250 }