/******************************************************************************* * 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.swing; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; import java.util.Collection; import java.util.EnumSet; import java.util.Map; import org.simantics.g2d.element.ElementClass; import org.simantics.g2d.element.ElementHints; import org.simantics.g2d.element.IElement; import org.simantics.g2d.element.SceneGraphNodeKey; import org.simantics.g2d.element.handler.ElementHandler; import org.simantics.g2d.element.handler.InternalSize; import org.simantics.g2d.element.handler.Outline; import org.simantics.g2d.element.handler.SceneGraph; import org.simantics.g2d.element.handler.StaticSymbol; import org.simantics.g2d.element.handler.Transform; import org.simantics.g2d.element.handler.impl.SimpleElementLayers; import org.simantics.g2d.element.handler.impl.StaticSymbolImpl; import org.simantics.g2d.elementclass.MonitorHandler; import org.simantics.g2d.image.Image; import org.simantics.g2d.image.ProviderUtils; import org.simantics.g2d.image.impl.AbstractImage; import org.simantics.scenegraph.Node; import org.simantics.scenegraph.g2d.G2DParentNode; import org.simantics.utils.datastructures.cache.IFactory; import org.simantics.utils.datastructures.cache.IProvider; import org.simantics.utils.datastructures.cache.ProvisionException; import org.simantics.utils.datastructures.hints.IHintContext.Key; /** * @author Tuukka Lehtonen */ public class SymbolMonitorClass { public static final Key KEY_SG_NODE = new SceneGraphNodeKey(Node.class, "SYMBOL_MONITOR_SG_NODE"); public static class MonitorHandlerImpl implements MonitorHandler { private static final long serialVersionUID = -4258875745321808416L; public static final MonitorHandler INSTANCE = new MonitorHandlerImpl(); } public static void update(IElement e) { SymbolMonitorSGNode node = e.getElementClass().getAtMostOneItemOfClass(SymbolMonitorSGNode.class); node.update(e); } public static void cleanup(IElement e) { SymbolMonitorSGNode node = e.getElementClass().getAtMostOneItemOfClass(SymbolMonitorSGNode.class); node.cleanup(e); } static final Rectangle2D DEFAULT_BOX = new Rectangle2D.Double(0, 0, 0, 0); static Shape createMonitor(IElement e) { return DEFAULT_BOX; } static Path2D makePath(double x, double y, double w, double h) { Path2D path = new Path2D.Double(); path.moveTo(x, y); path.lineTo(x+w, y); path.lineTo(x+w, y+h); path.lineTo(x, y+h); path.closePath(); return path; } public static final Shape BOX_SHAPE = new Rectangle(-1, -1, 2, 2); public static class SymbolMonitorSGNode implements SceneGraph, InternalSize, Outline { private static final long serialVersionUID = -106278359626957687L; static final SymbolMonitorSGNode INSTANCE = new SymbolMonitorSGNode(); @Override public void init(final IElement e, final G2DParentNode parent) { // Create node if it doesn't exist yet SymbolMonitorNode node = (SymbolMonitorNode)e.getHint(KEY_SG_NODE); if(node == null || node.getBounds() == null || node.getParent() != parent) { // FIXME : symbol monitor node is not disposed properly, so currently this code is commented out. //node = parent.addNode(ElementUtils.generateNodeId(e), SymbolMonitorNode.class); //e.setHint(KEY_SG_NODE, node); } update(e); } public void update(IElement e) { } @Override public void cleanup(IElement e) { SymbolMonitorNode node = (SymbolMonitorNode)e.removeHint(KEY_SG_NODE); if (node != null) node.remove(); } @Override public Rectangle2D getBounds(IElement e, Rectangle2D size) { Rectangle2D shape = new Rectangle2D.Double(0, 0, 0, 0); SymbolMonitorNode node = (SymbolMonitorNode)e.getHint(KEY_SG_NODE); if(node != null && node.getBounds() != null) { shape = node.getBounds().getBounds2D(); } if(size != null) size.setRect(shape); return shape; } @Override public Shape getElementShape(IElement e) { Shape shape = new Rectangle2D.Double(0, 0, 0, 0); SymbolMonitorNode node = (SymbolMonitorNode)e.getHint(KEY_SG_NODE); if(node != null && node.getBounds() != null) { shape = node.getBounds(); } return shape; } } public static class Transformer implements Transform { private static final long serialVersionUID = -3704887325602085677L; public static final Transformer INSTANCE = new Transformer(null); Double aspectRatio; public Transformer() { this(null); } public Transformer(Double aspectRatio) { this.aspectRatio = aspectRatio; } @Override public AffineTransform getTransform(IElement e) { AffineTransform at = e.getHint(ElementHints.KEY_TRANSFORM); IElement parentElement = e.getHint(ElementHints.KEY_PARENT_ELEMENT); if (parentElement == null) return at; Transform parentTransform = parentElement.getElementClass().getSingleItem(Transform.class); assert(parentTransform!=null); AffineTransform result = (AffineTransform)at.clone(); result.preConcatenate(parentTransform.getTransform(parentElement)); return result; } @Override public void setTransform(IElement e, AffineTransform at) { e.setHint(ElementHints.KEY_TRANSFORM, at.clone()); } } static class MonitorImageFactory implements IFactory { private double staticScaleX = 1, staticScaleY = 1; public MonitorImageFactory(double staticScaleX, double staticScaleY) { this.staticScaleX = staticScaleX; this.staticScaleY = staticScaleY; } @Override public Image get() throws ProvisionException { return new AbstractImage() { Shape path = BOX_SHAPE; @Override public Rectangle2D getBounds() { return path.getBounds2D(); } @Override public EnumSet getFeatures() { return EnumSet.of(Feature.Vector); } @Override public Shape getOutline() { return path; } @Override public Node init(G2DParentNode parent) { SymbolMonitorNode node = parent.getOrCreateNode(""+hashCode(), SymbolMonitorNode.class); node.setText(""); node.setBounds(new Rectangle2D.Double(0, 0, 50, 22)); node.setText("Drop Me"); node.setTransform(AffineTransform.getScaleInstance(staticScaleX, staticScaleY)); return node; } }; } } static final IProvider MONITOR_IMAGE = ProviderUtils.reference( ProviderUtils.cache( ProviderUtils.rasterize( new MonitorImageFactory(0.5, 0.5) ))); static final StaticSymbol MONITOR_SYMBOL = new StaticSymbolImpl( MONITOR_IMAGE.get() ); public static final ElementClass MONITOR_CLASS = ElementClass.compile( MonitorHandlerImpl.INSTANCE, Transformer.INSTANCE, SymbolMonitorSGNode.INSTANCE, SimpleElementLayers.INSTANCE, MONITOR_SYMBOL ); // staticScale{X,Y} define the scale of the static monitor image public static ElementClass create(IElement parentElement, Map substitutions, Collection path, double staticScaleX, double staticScaleY, ElementHandler... extraHandlers) { // Bit of a hack to be able to define the scale IProvider staticMonitorSymbolProvider = ProviderUtils.reference( ProviderUtils.cache( ProviderUtils .rasterize( new MonitorImageFactory(staticScaleX, staticScaleY)))); StaticSymbol staticMonitorSymbol = new StaticSymbolImpl( staticMonitorSymbolProvider.get() ); return ElementClass.compile( MonitorHandlerImpl.INSTANCE, Transformer.INSTANCE, SymbolMonitorSGNode.INSTANCE, SimpleElementLayers.INSTANCE, staticMonitorSymbol ).newClassWith(extraHandlers); } }