ShapeNode with separate stroke and fill paints
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / nodes / ShapeNode2.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  * This is similar to ShapeNode, but allows separate stroke and fill colors. 
32  * Due to API changes, I've done separate implementation. -MLuu 
33  * 
34  * 
35  * @author luukkainen
36  * @author J-P Laine
37  * @author Tuukka Lehtonen
38  * 
39  */
40 public class ShapeNode2 extends G2DNode implements InitValueSupport {
41
42         private static final long serialVersionUID = -5700299566608619380L;
43
44         protected static final Stroke DEFAULT_STROKE = new BasicStroke(2);
45
46     protected Shape shape = null;
47     protected Stroke stroke = DEFAULT_STROKE;
48     protected Paint strokeColor = Color.BLACK;
49     protected Paint fillColor = null;
50     protected boolean scaleStroke = false;
51     protected boolean scaleShape = false;
52
53     protected transient Shape dynamicShape = null;
54     protected transient Stroke dynamicStroke = null;
55     protected transient Paint dynamicStrokeColor = null;
56     protected transient Paint dynamicFillColor = null;
57     protected transient Boolean dynamicScaleStroke = null;
58     protected transient Boolean dynamicScaleShape = null;
59
60     @PropertySetter("shape")
61     @SyncField("shape")
62     public void setShape(Shape shape) {
63         this.shape = shape;
64         repaint();
65     }
66
67     @PropertySetter("stroke")
68     @SyncField("stroke")
69     public void setStroke(Stroke stroke) {
70         this.stroke = stroke;
71     }
72
73     @PropertySetter("strokeColor")
74     @SyncField("strokeColor")
75     public void setStrokeColor(Paint color) {
76         this.strokeColor = color;
77     }
78
79     @PropertySetter("fillColor")
80     @SyncField("fillColor")
81     public void setFillColor(Paint color) {
82         this.fillColor = color;
83     }
84
85
86     @SyncField("scaleStroke")
87     public void setScaleStroke(boolean scaleStroke) {
88         this.scaleStroke = scaleStroke;
89     }
90
91     @SyncField("scaleShape")
92     public void setScaleShape(boolean scaleShape) {
93         this.scaleShape = scaleShape;
94     }
95
96     @Override
97     public void render(Graphics2D g2d) {
98         Shape shape = dynamicShape != null ? dynamicShape : this.shape;
99         if (shape == null)
100             return;
101
102         AffineTransform ot = setupRender(g2d);
103         renderShape(g2d, shape);
104         if (ot != null)
105             g2d.setTransform(ot);
106     }
107
108     /**
109      * @param g2d
110      * @return current transform
111      */
112     protected AffineTransform setupRender(Graphics2D g2d) {
113         AffineTransform old = null;
114         if (!transform.isIdentity()) {
115             old = g2d.getTransform();
116             g2d.transform(transform);
117         }
118
119         
120         boolean scaleShape = Boolean.TRUE.equals(dynamicScaleShape) ? true : this.scaleShape;
121         if (scaleShape) {
122             double xs = g2d.getTransform().getScaleX();
123             double ys = g2d.getTransform().getScaleY();
124             g2d.scale(1/xs, 1/ys);
125         }
126
127         return old;
128     }
129
130     protected void renderShape(Graphics2D g2d, Shape s) {
131         Paint color = dynamicFillColor != null ? dynamicFillColor : this.fillColor;
132         if (color != null) {
133                 g2d.setPaint(color);
134             g2d.fill(s);
135         }
136
137         Stroke stroke = dynamicStroke != null ? dynamicStroke : this.stroke;
138         if (stroke != null) {
139                 color = dynamicStrokeColor != null ? dynamicStrokeColor : this.strokeColor;
140             if (color != null) g2d.setPaint(color);
141
142             boolean scaleStroke = Boolean.TRUE.equals(dynamicScaleStroke) ? true : this.scaleStroke;
143             if (scaleStroke && stroke instanceof BasicStroke) {
144                BasicStroke bs = GeometryUtils.scaleStroke(stroke, (float) (1.0 / GeometryUtils.getScale(g2d.getTransform())));
145                g2d.setStroke(bs);
146             } else {
147                 g2d.setStroke(stroke);
148             }
149             
150             g2d.draw(s);
151         }
152     }
153
154     @Override
155     public Rectangle2D getBoundsInLocal() {
156         if(shape == null) return null;
157         return shape.getBounds2D();
158     }
159
160     public void setValue(String key, Object value) {
161         if ("shape".equals(key))
162             dynamicShape = (Shape) value;
163         else if ("stroke".equals(key))
164             dynamicStroke = (Stroke) value;
165         else if ("strokeColor".equals(key))
166             dynamicStrokeColor = (Paint) value;
167         else if ("fillColor".equals(key))
168             dynamicFillColor = (Paint) value;
169         else if ("scaleStroke".equals(key))
170             dynamicScaleStroke = (Boolean) value;
171         else if ("scaleShape".equals(key))
172             dynamicScaleShape = (Boolean) value;
173 //        else super.setValue(key, value);
174     }
175
176     @Override
177     public void initValues() {
178         dynamicShape = null;
179         dynamicStroke = null;
180         dynamicStrokeColor = null;
181         dynamicFillColor = null;
182         dynamicScaleStroke = null;
183         dynamicScaleShape = null;
184     }
185
186     @Override
187     public String toString() {
188         return super.toString() + " [shape=" + shape + ",color=" + strokeColor + ",fill=" + fillColor +"]";
189     }
190
191 }