/******************************************************************************* * 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.Paint; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import org.simantics.scenegraph.g2d.G2DNode; import org.simantics.scenegraph.utils.GeometryUtils; import org.simantics.scenegraph.utils.InitValueSupport; /** * A scene graph node that renders a specified AWT {@link Shape} by optionally * filling or drawing it. * * If filling is enabled, it will be performed before stroking the shape. * * @author J-P Laine * @author Tuukka Lehtonen * * TODO: separate paint for stroke and fill */ public class ShapeNode extends G2DNode implements InitValueSupport { private static final long serialVersionUID = 8508750881358776559L; protected static final Stroke DEFAULT_STROKE = new BasicStroke(2); protected Shape shape = null; protected Stroke stroke = DEFAULT_STROKE; protected Paint color = Color.BLACK; protected boolean fill = false; protected boolean scaleStroke = false; protected boolean scaleShape = false; protected transient Shape dynamicShape = null; protected transient Stroke dynamicStroke = null; protected transient Paint dynamicColor = null; protected transient Boolean dynamicFill = null; protected transient Boolean dynamicScaleStroke = null; protected transient Boolean dynamicScaleShape = null; @PropertySetter("shape") @SyncField("shape") public void setShape(Shape shape) { this.shape = shape; repaint(); } @PropertySetter("stroke") @SyncField("stroke") public void setStroke(Stroke stroke) { this.stroke = stroke; } @PropertySetter("color") @SyncField("color") public void setColor(Paint color) { this.color = color; } @SyncField("fill") public void setFill(boolean fill) { this.fill = fill; } @SyncField("scaleStroke") public void setScaleStroke(boolean scaleStroke) { this.scaleStroke = scaleStroke; } @SyncField("scaleShape") public void setScaleShape(boolean scaleShape) { this.scaleShape = scaleShape; } @Override public void render(Graphics2D g2d) { Shape shape = dynamicShape != null ? dynamicShape : this.shape; if (shape == null) return; AffineTransform ot = setupRender(g2d); renderShape(g2d, shape); if (ot != null) g2d.setTransform(ot); } /** * @param g2d * @return current transform */ protected AffineTransform setupRender(Graphics2D g2d) { AffineTransform old = null; if (!transform.isIdentity()) { old = g2d.getTransform(); g2d.transform(transform); } Paint color = dynamicColor != null ? dynamicColor : this.color; if (color != null) g2d.setPaint(color); Stroke stroke = dynamicStroke != null ? dynamicStroke : this.stroke; if (stroke != null) { boolean scaleStroke = Boolean.TRUE.equals(dynamicScaleStroke) ? true : this.scaleStroke; if (scaleStroke && stroke instanceof BasicStroke) { BasicStroke bs = GeometryUtils.scaleStroke(stroke, (float) (1.0 / GeometryUtils.getScale(g2d.getTransform()))); g2d.setStroke(bs); } else { g2d.setStroke(stroke); } } boolean scaleShape = Boolean.TRUE.equals(dynamicScaleShape) ? true : this.scaleShape; if (scaleShape) { double xs = g2d.getTransform().getScaleX(); double ys = g2d.getTransform().getScaleY(); g2d.scale(1/xs, 1/ys); } return old; } protected void renderShape(Graphics2D g2d, Shape s) { boolean fill = Boolean.TRUE.equals(dynamicFill) ? true : this.fill; if (fill) g2d.fill(s); Stroke stroke = dynamicStroke != null ? dynamicStroke : this.stroke; if (stroke != null) g2d.draw(s); } @Override public Rectangle2D getBoundsInLocal() { if(shape == null) return null; return shape.getBounds2D(); } public void setValue(String key, Object value) { if ("shape".equals(key)) dynamicShape = (Shape) value; else if ("stroke".equals(key)) dynamicStroke = (Stroke) value; else if ("color".equals(key)) dynamicColor = (Paint) value; else if ("fill".equals(key)) dynamicFill = (Boolean) value; else if ("scaleStroke".equals(key)) dynamicScaleStroke = (Boolean) value; else if ("scaleShape".equals(key)) dynamicScaleShape = (Boolean) value; // else super.setValue(key, value); } @Override public void initValues() { dynamicShape = null; dynamicStroke = null; dynamicColor = null; dynamicFill = null; dynamicScaleStroke = null; dynamicScaleShape = null; } @Override public String toString() { return super.toString() + " [shape=" + shape + ",color=" + color + "]"; } }