]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/SVGHolderNode.java
Sync git svn branch with SVN repository r33269.
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / nodes / SVGHolderNode.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.scenegraph.g2d.nodes;\r
13 \r
14 import java.awt.BasicStroke;\r
15 import java.awt.Color;\r
16 import java.awt.Graphics2D;\r
17 import java.awt.Shape;\r
18 import java.awt.geom.AffineTransform;\r
19 import java.awt.geom.Rectangle2D;\r
20 import org.simantics.scenegraph.g2d.G2DParentNode;\r
21 import org.simantics.scenegraph.g2d.IG2DNode;\r
22 \r
23 /**\r
24  * \r
25  * Holder node that scales content to fit (and scales SVG inside those bounds)\r
26  * \r
27  * @author jplaine\r
28  *\r
29  */\r
30 public class SVGHolderNode extends G2DParentNode {\r
31     /**\r
32      * \r
33      */\r
34     private static final long serialVersionUID = 8698435757824280001L;\r
35 \r
36     protected Rectangle2D bounds = null;\r
37     protected Float       borderWidth = null;\r
38     \r
39     \r
40     @PropertySetter("VariableFilter")\r
41     public void setScript(String script) {\r
42         for(IG2DNode node : getSortedNodes()) // Pass value to children\r
43                 if(node instanceof AnimatedSVGNode) {\r
44                         ((AnimatedSVGNode)node).setScript(script);\r
45                 }\r
46     }\r
47     \r
48     @PropertySetter("SVG")\r
49     public void setData(String data) {\r
50         for(IG2DNode node : getSortedNodes()) // Pass value to children\r
51                 if(node instanceof AnimatedSVGNode) {\r
52                         ((AnimatedSVGNode)node).setData(data);\r
53                 }\r
54     }\r
55 \r
56     @PropertySetter("Stroke Width")\r
57     @SyncField("border")\r
58     public void setBorderWidth(Float borderWidth) {\r
59         this.borderWidth = borderWidth;\r
60     }\r
61 \r
62     @PropertySetter("Bounds")\r
63     @SyncField("bounds")\r
64     public void setBounds(Rectangle2D bounds) {\r
65         this.bounds = bounds;\r
66     }\r
67 \r
68     @Override\r
69     public void render(Graphics2D g2d) {\r
70         Rectangle2D cb = getBoundsInLocal(false);\r
71         double scaleX = bounds.getWidth() / cb.getWidth();\r
72         double scaleY = bounds.getHeight() / cb.getHeight();\r
73         double scale = Math.min(scaleX, scaleY);\r
74 \r
75         if(borderWidth != null && borderWidth > 0.0f && bounds != null) {\r
76             Graphics2D g2 = (Graphics2D)g2d.create();\r
77             g2.transform(transform);\r
78             g2.setStroke(new BasicStroke(this.borderWidth));\r
79             g2.setColor(Color.BLACK);\r
80             g2.draw(bounds);\r
81             g2.dispose();\r
82         }\r
83 \r
84         @SuppressWarnings("unused")\r
85         int noBounds = 0;\r
86         @SuppressWarnings("unused")\r
87         int clipped = 0;\r
88         @SuppressWarnings("unused")\r
89         int rendered = 0;\r
90 \r
91         AffineTransform ot = g2d.getTransform();\r
92         g2d.transform(transform);\r
93 \r
94         g2d.translate(-cb.getMinX()*scale+bounds.getMinX(), -cb.getMinY()*scale+bounds.getMinY());\r
95         g2d.scale(scale, scale);\r
96 \r
97         // Get transformed clip bounds\r
98         Shape clipShape = g2d.getClip();\r
99         Rectangle2D bounds = null;\r
100         if (clipShape instanceof Rectangle2D)\r
101             bounds = (Rectangle2D) clipShape;\r
102         else if (clipShape != null)\r
103             bounds = clipShape.getBounds2D();\r
104 \r
105         boolean noClipBounds = bounds == null;\r
106 \r
107         for(IG2DNode node : getSortedNodes()) {\r
108             Rectangle2D localBounds = node.getBoundsInLocal();\r
109             boolean hasNoBounds = localBounds == null;\r
110             boolean visible = false;\r
111             if (!noClipBounds && !hasNoBounds) {\r
112                 visible = node.intersects(bounds);\r
113             } else {\r
114                 ++noBounds;\r
115             }\r
116             if (noClipBounds || hasNoBounds || visible) {\r
117                 // TODO: consider removing this g2d.create ?\r
118                 // Will definitely current cause bugs to appear.\r
119                 if (node.validate()) {\r
120                     node.render(g2d);\r
121                 }\r
122                 ++rendered;\r
123             } else {\r
124                 ++clipped;\r
125             }\r
126         }\r
127 \r
128         g2d.setTransform(ot);\r
129     }\r
130 \r
131     @Override\r
132     public Rectangle2D getBoundsInLocal() {\r
133         return bounds; // FIXME: not sure if it's a good idea to return different value than the getBoundsInLocal(boolean nulls) returns..\r
134     }\r
135 \r
136 }\r