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