]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/ShapeNode.java
G2DParentNode handles "undefined" child bounds separately
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / nodes / ShapeNode.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.scenegraph.g2d.nodes;
13
14 import java.awt.BasicStroke;
15 import java.awt.Color;
16 import java.awt.Graphics2D;
17 import java.awt.Paint;
18 import java.awt.Shape;
19 import java.awt.Stroke;
20 import java.awt.geom.AffineTransform;
21 import java.awt.geom.Rectangle2D;
22
23 import org.simantics.scenegraph.g2d.G2DNode;
24 import org.simantics.scenegraph.utils.GeometryUtils;
25 import org.simantics.scenegraph.utils.InitValueSupport;
26
27 /**
28  * A scene graph node that renders a specified AWT {@link Shape} by optionally
29  * filling or drawing it.
30  * 
31  * If filling is enabled, it will be performed before stroking the shape.
32  * 
33  * @author J-P Laine
34  * @author Tuukka Lehtonen
35  * 
36  * TODO: separate paint for stroke and fill
37  */
38 public class ShapeNode extends G2DNode implements InitValueSupport {
39
40     private static final long serialVersionUID = 8508750881358776559L;
41
42     protected static final Stroke DEFAULT_STROKE = new BasicStroke(2);
43
44     protected Shape shape = null;
45     protected Stroke stroke = DEFAULT_STROKE;
46     protected Paint color = Color.BLACK;
47     protected boolean fill = false;
48     protected boolean scaleStroke = false;
49     protected boolean scaleShape = false;
50
51     protected transient Shape dynamicShape = null;
52     protected transient Stroke dynamicStroke = null;
53     protected transient Paint dynamicColor = null;
54     protected transient Boolean dynamicFill = null;
55     protected transient Boolean dynamicScaleStroke = null;
56     protected transient Boolean dynamicScaleShape = null;
57
58     @PropertySetter("shape")
59     @SyncField("shape")
60     public void setShape(Shape shape) {
61         this.shape = shape;
62         repaint();
63     }
64
65     @PropertySetter("stroke")
66     @SyncField("stroke")
67     public void setStroke(Stroke stroke) {
68         this.stroke = stroke;
69     }
70
71     @PropertySetter("color")
72     @SyncField("color")
73     public void setColor(Paint color) {
74         this.color = color;
75     }
76
77     @SyncField("fill")
78     public void setFill(boolean fill) {
79         this.fill = fill;
80     }
81
82     @SyncField("scaleStroke")
83     public void setScaleStroke(boolean scaleStroke) {
84         this.scaleStroke = scaleStroke;
85     }
86
87     @SyncField("scaleShape")
88     public void setScaleShape(boolean scaleShape) {
89         this.scaleShape = scaleShape;
90     }
91
92     @Override
93     public void render(Graphics2D g2d) {
94         Shape shape = dynamicShape != null ? dynamicShape : this.shape;
95         if (shape == null)
96             return;
97
98         AffineTransform ot = setupRender(g2d);
99         renderShape(g2d, shape);
100         if (ot != null)
101             g2d.setTransform(ot);
102     }
103
104     /**
105      * @param g2d
106      * @return current transform
107      */
108     protected AffineTransform setupRender(Graphics2D g2d) {
109         AffineTransform old = null;
110         if (!transform.isIdentity()) {
111             old = g2d.getTransform();
112             g2d.transform(transform);
113         }
114
115         Paint color = dynamicColor != null ? dynamicColor : this.color;
116         if (color != null) g2d.setPaint(color);
117
118         Stroke stroke = dynamicStroke != null ? dynamicStroke : this.stroke;
119         if (stroke != null) {
120             boolean scaleStroke = Boolean.TRUE.equals(dynamicScaleStroke) ? true : this.scaleStroke;
121             if (scaleStroke && stroke instanceof BasicStroke) {
122                 BasicStroke bs = GeometryUtils.scaleStroke(stroke, (float) (1.0 / GeometryUtils.getScale(g2d.getTransform())));
123                 g2d.setStroke(bs);
124             } else {
125                 g2d.setStroke(stroke);
126             }
127         }
128
129         boolean scaleShape = Boolean.TRUE.equals(dynamicScaleShape) ? true : this.scaleShape;
130         if (scaleShape) {
131             double xs = g2d.getTransform().getScaleX();
132             double ys = g2d.getTransform().getScaleY();
133             g2d.scale(1/xs, 1/ys);
134         }
135
136         return old;
137     }
138
139     protected void renderShape(Graphics2D g2d, Shape s) {
140         boolean fill = Boolean.TRUE.equals(dynamicFill) ? true : this.fill;
141         if (fill)
142             g2d.fill(s);
143
144         Stroke stroke = dynamicStroke != null ? dynamicStroke : this.stroke;
145         if (stroke != null)
146             g2d.draw(s);
147     }
148
149     @Override
150     public Rectangle2D getBoundsInLocal() {
151         if(shape == null) return null;
152         return shape.getBounds2D();
153     }
154
155     public void setValue(String key, Object value) {
156         if ("shape".equals(key))
157             dynamicShape = (Shape) value;
158         else if ("stroke".equals(key))
159             dynamicStroke = (Stroke) value;
160         else if ("color".equals(key))
161             dynamicColor = (Paint) value;
162         else if ("fill".equals(key))
163             dynamicFill = (Boolean) value;
164         else if ("scaleStroke".equals(key))
165             dynamicScaleStroke = (Boolean) value;
166         else if ("scaleShape".equals(key))
167             dynamicScaleShape = (Boolean) value;
168 //        else super.setValue(key, value);
169     }
170
171     @Override
172     public void initValues() {
173         dynamicShape = null;
174         dynamicStroke = null;
175         dynamicColor = null;
176         dynamicFill = null;
177         dynamicScaleStroke = null;
178         dynamicScaleShape = null;
179     }
180
181     @Override
182     public String toString() {
183         return super.toString() + " [shape=" + shape + ",color=" + color + "]";
184     }
185
186 }