/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.scenegraph.g2d.nodes; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.scenegraph.g2d.IG2DNode; /** * * Holder node that scales content to fit (and scales SVG inside those bounds) * * @author jplaine * */ public class SVGHolderNode extends G2DParentNode { /** * */ private static final long serialVersionUID = 8698435757824280001L; protected Rectangle2D bounds = null; protected Float borderWidth = null; @PropertySetter("VariableFilter") public void setScript(String script) { for(IG2DNode node : getSortedNodes()) // Pass value to children if(node instanceof AnimatedSVGNode) { ((AnimatedSVGNode)node).setScript(script); } } @PropertySetter("SVG") public void setData(String data) { for(IG2DNode node : getSortedNodes()) // Pass value to children if(node instanceof AnimatedSVGNode) { ((AnimatedSVGNode)node).setData(data); } } @PropertySetter("Stroke Width") @SyncField("border") public void setBorderWidth(Float borderWidth) { this.borderWidth = borderWidth; } @PropertySetter("Bounds") @SyncField("bounds") public void setBounds(Rectangle2D bounds) { this.bounds = bounds; } @Override public void render(Graphics2D g2d) { Rectangle2D cb = getBoundsInLocal(false); double scaleX = bounds.getWidth() / cb.getWidth(); double scaleY = bounds.getHeight() / cb.getHeight(); double scale = Math.min(scaleX, scaleY); if(borderWidth != null && borderWidth > 0.0f && bounds != null) { Graphics2D g2 = (Graphics2D)g2d.create(); g2.transform(transform); g2.setStroke(new BasicStroke(this.borderWidth)); g2.setColor(Color.BLACK); g2.draw(bounds); g2.dispose(); } @SuppressWarnings("unused") int noBounds = 0; @SuppressWarnings("unused") int clipped = 0; @SuppressWarnings("unused") int rendered = 0; AffineTransform ot = g2d.getTransform(); g2d.transform(transform); g2d.translate(-cb.getMinX()*scale+bounds.getMinX(), -cb.getMinY()*scale+bounds.getMinY()); g2d.scale(scale, scale); // Get transformed clip bounds Shape clipShape = g2d.getClip(); Rectangle2D bounds = null; if (clipShape instanceof Rectangle2D) bounds = (Rectangle2D) clipShape; else if (clipShape != null) bounds = clipShape.getBounds2D(); boolean noClipBounds = bounds == null; for(IG2DNode node : getSortedNodes()) { Rectangle2D localBounds = node.getBoundsInLocal(); boolean hasNoBounds = localBounds == null; boolean visible = false; if (!noClipBounds && !hasNoBounds) { visible = node.intersects(bounds); } else { ++noBounds; } if (noClipBounds || hasNoBounds || visible) { // TODO: consider removing this g2d.create ? // Will definitely current cause bugs to appear. if (node.validate()) { node.render(g2d); } ++rendered; } else { ++clipped; } } g2d.setTransform(ot); } @Override public Rectangle2D getBoundsInLocal() { return bounds; // FIXME: not sure if it's a good idea to return different value than the getBoundsInLocal(boolean nulls) returns.. } }