/******************************************************************************* * 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.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import org.simantics.scenegraph.g2d.G2DNode; import org.simantics.scenegraph.utils.GeometryUtils; public class SelectionNode extends G2DNode implements Decoration { /** * */ private static final long serialVersionUID = -2879575230419873230L; public transient static final BasicStroke SELECTION_STROKE = new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f, new float[] { 5.0f, 5.0f }, 0.0f); protected Rectangle2D bounds = null; protected Color color = null; protected transient Rectangle2D rect; protected transient BasicStroke scaledStroke; protected transient double previousScaleRecip = Double.NaN; protected boolean ignore = false; protected double paddingFactor = 5.0; protected int selectionId; public int getSelectionId() { return selectionId; } public void setIgnore(boolean value) { ignore = value; } public void setPaddingFactor(double factor) { paddingFactor = factor; } @SyncField({"transform", "bounds", "color"}) public void init(int selectionId, AffineTransform transform, Rectangle2D bounds, Color color) { this.selectionId = selectionId; this.transform = transform; this.bounds = bounds; this.color = color; } public void init(AffineTransform transform, Rectangle2D bounds, Color color) { init(0, transform, bounds, color); } @Override public void render(Graphics2D g) { if (bounds == null) return; if (ignore) return; // Prevent exceptions during rendering. if (transform.getDeterminant() == 0) return; AffineTransform ot = g.getTransform(); g.setColor(color); g.transform(transform); AffineTransform tx = g.getTransform(); //System.out.println("tx: " + tx); double scale = GeometryUtils.getScale(tx); //System.out.println("scale: " + scale); double scaleRecip = 1.0 / scale; //System.out.println("scale: " + scaleRecip); // Prevent stroke reallocation while panning. // Zooming will trigger reallocation. if (scaledStroke == null || scaleRecip != previousScaleRecip) { scaledStroke = GeometryUtils.scaleStroke( SELECTION_STROKE, (float) scaleRecip); previousScaleRecip = scaleRecip; } g.setStroke(scaledStroke); double padding = paddingFactor * scaleRecip; double paddingX = padding; double paddingY = padding; if (rect == null) rect = new Rectangle2D.Double(); rect.setFrame(bounds.getMinX() - paddingX, bounds.getMinY() - paddingY, bounds.getWidth() + 2.0*paddingX, bounds.getHeight() + 2.0*paddingY); g.draw(rect); g.setTransform(ot); } public Rectangle2D getRect() { return transform.createTransformedShape(rect).getBounds2D(); } @Override public Rectangle2D getBoundsInLocal() { return bounds; } }