1 /*******************************************************************************
\r
2 * Copyright (c) 2010 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.sysdyn.ui.elements2.connections;
\r
14 import java.awt.BasicStroke;
\r
15 import java.awt.Color;
\r
16 import java.awt.Font;
\r
17 import java.awt.Graphics2D;
\r
18 import java.awt.Stroke;
\r
19 import java.awt.event.MouseEvent;
\r
20 import java.awt.event.MouseListener;
\r
21 import java.awt.event.MouseMotionListener;
\r
22 import java.awt.geom.Arc2D;
\r
23 import java.awt.geom.Path2D;
\r
24 import java.awt.geom.Point2D;
\r
25 import java.awt.geom.Rectangle2D;
\r
26 import java.beans.PropertyChangeEvent;
\r
27 import java.beans.PropertyChangeListener;
\r
29 import org.simantics.diagram.elements.TextNode;
\r
30 import org.simantics.scenegraph.ISelectionPainterNode;
\r
31 import org.simantics.scenegraph.g2d.events.ISGMouseEvent;
\r
32 import org.simantics.scenegraph.utils.NodeUtil;
\r
33 import org.simantics.sysdyn.ui.editor.routing.DependencyRouter;
\r
34 import org.simantics.utils.datastructures.Pair;
\r
36 public class DependencyNode extends TextNode implements ISelectionPainterNode, MouseListener, MouseMotionListener {
\r
38 public static final String INSIDE = "Inside";
\r
39 public static final String OUTSIDE = "Outside";
\r
41 private static final long serialVersionUID = 1294351381209071074L;
\r
43 private static final BasicStroke STROKE = new BasicStroke(1.0f);
\r
45 private Color color;
\r
46 private Stroke stroke;
\r
47 private Rectangle2D beginBounds;
\r
48 private Rectangle2D endBounds;
\r
49 private double angle = 0.1;
\r
50 private String side;
\r
51 private transient Pair<Arc2D, Path2D> shapes = new Pair<Arc2D, Path2D>(new Arc2D.Double(), new Path2D.Double());
\r
53 transient public boolean hover = false;
\r
55 private transient PropertyChangeListener fieldListener = null;
\r
58 public void init() {
\r
60 NodeUtil.getEventDelegator(this).addMouseListener(this);
\r
61 NodeUtil.getEventDelegator(this).addMouseMotionListener(this);
\r
65 public void init(String text, String side, Font font, Color color, double x, double y, double scale) {
\r
66 super.init(text, font, color, x, y, scale);
\r
71 public void cleanup() {
\r
72 NodeUtil.getEventDelegator(this).removeMouseListener(this);
\r
73 NodeUtil.getEventDelegator(this).removeMouseMotionListener(this);
\r
77 public void setFieldListener(PropertyChangeListener listener) {
\r
78 this.fieldListener = listener;
\r
82 public void commitProperty(String field, Object value) {
\r
83 if(fieldListener != null) {
\r
84 fieldListener.propertyChange(new PropertyChangeEvent(this, field, null, value));
\r
88 @PropertySetter("color")
\r
90 public void setColor(Color color) {
\r
94 @PropertySetter("stroke")
\r
95 @SyncField("stroke")
\r
96 public void setStroke(Stroke stroke) {
\r
97 this.stroke = stroke;
\r
100 @PropertySetter("beginBounds")
\r
101 @SyncField("beginBounds")
\r
102 public void setBeginBounds(Rectangle2D beginBounds) {
\r
103 this.beginBounds = beginBounds;
\r
106 @PropertySetter("endBounds")
\r
107 @SyncField("endBounds")
\r
108 public void setEndBounds(Rectangle2D endBounds) {
\r
109 this.endBounds = endBounds;
\r
112 @PropertySetter("angle")
\r
113 @SyncField("angle")
\r
114 public void setAngle(Double angle) {
\r
115 this.angle = angle.doubleValue();
\r
116 if(this.beginBounds != null && this.endBounds != null)
\r
117 this.shapes = DependencyRouter.createArrowShape(this.shapes, this.beginBounds, this.endBounds, this.angle);
\r
120 @PropertySetter("shapes")
\r
121 @SyncField("shapes")
\r
122 public void setShapes(Pair<Arc2D, Path2D> shapes) {
\r
123 this.shapes = shapes;
\r
126 public Color getColor() {
\r
130 public Stroke getStroke() {
\r
134 public Rectangle2D getBeginBounds() {
\r
135 return beginBounds;
\r
138 public Rectangle2D getEndBounds() {
\r
142 public double getAngle() {
\r
146 public Pair<Arc2D, Path2D> getShapes() {
\r
153 public void render(Graphics2D g) {
\r
154 if(beginBounds == null || endBounds == null) return;
\r
156 // Removed to let the global control handle rendering quality issues.
\r
157 //g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
\r
159 boolean selected = NodeUtil.isSelected(this, 2);
\r
161 g.setColor(Color.PINK);
\r
162 g.setStroke(STROKE);
\r
163 g.draw(shapes.first);
\r
164 g.fill(shapes.second);
\r
165 if(color != null) g.setColor(color);
\r
166 g.setStroke(stroke);
\r
167 g.draw(shapes.first);
\r
168 g.fill(shapes.second);
\r
170 g.setColor(Color.LIGHT_GRAY);
\r
171 g.setStroke(STROKE);
\r
172 g.draw(shapes.first);
\r
173 g.fill(shapes.second);
\r
174 if(color != null) g.setColor(color);
\r
175 g.setStroke(stroke);
\r
176 g.draw(shapes.first);
\r
177 g.fill(shapes.second);
\r
179 if(color != null) g.setColor(color);
\r
180 if(stroke != null) g.setStroke(stroke);
\r
181 g.draw(shapes.first);
\r
182 g.fill(shapes.second);
\r
186 double angleRad = angle > 0 ?
\r
187 Math.toRadians(shapes.first.getAngleStart() + shapes.first.getAngleExtent()) :
\r
188 Math.toRadians(shapes.first.getAngleStart());
\r
189 Point2D point = angle > 0 ? shapes.first.getEndPoint() : shapes.first.getStartPoint();
\r
193 if(OUTSIDE.equals(side)) {
\r
197 double a = Math.toRadians(angle < 0 ? angle1 : angle2);
\r
198 double s = Math.sin(a) * 2;
\r
199 double c = Math.cos(a) * 3;
\r
201 g.translate(point.getX(), point.getY());
\r
202 g.rotate(-angleRad);
\r
204 g.rotate(angleRad);
\r
206 g.rotate(-angleRad);
\r
207 g.translate(-s, -c);
\r
208 g.rotate(angleRad);
\r
209 g.translate(-point.getX(), -point.getY());
\r
213 boolean pressHit = false;
\r
215 private boolean hitTest(MouseEvent event, double tolerance) {
\r
216 if(event instanceof ISGMouseEvent) {
\r
217 if(beginBounds == null || endBounds == null) return false;
\r
219 return Arcs.hitTest(beginBounds, endBounds, angle, ((ISGMouseEvent)event).getDoubleX(), ((ISGMouseEvent)event).getDoubleY(), tolerance);
\r
226 public Rectangle2D getBoundsInLocal() {
\r
231 public void mouseDragged(MouseEvent e) {
\r
232 if(pressHit && e instanceof ISGMouseEvent) {
\r
233 setAngle(Arcs.angleOfArc(
\r
234 beginBounds.getCenterX(), beginBounds.getCenterY(),
\r
235 ((ISGMouseEvent)e).getDoubleX(), ((ISGMouseEvent)e).getDoubleY(),
\r
236 endBounds.getCenterX(), endBounds.getCenterY()));
\r
241 public void mouseMoved(MouseEvent e) {
\r
242 boolean hit = hitTest(e, 3.0);
\r
250 public void mouseClicked(MouseEvent e) {
\r
251 // TODO Auto-generated method stub
\r
256 public void mousePressed(MouseEvent e) {
\r
257 boolean hit = hitTest(e, 3.0);
\r
260 commitProperty("angle", angle);
\r
266 public void mouseReleased(MouseEvent e) {
\r
267 boolean hit = hitTest(e, 3.0);
\r
269 commitProperty("angle", angle);
\r
274 public void mouseEntered(MouseEvent e) {
\r
275 // TODO Auto-generated method stub
\r
280 public void mouseExited(MouseEvent e) {
\r
281 // TODO Auto-generated method stub
\r