1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.participant;
14 import java.awt.Rectangle;
15 import java.awt.Shape;
16 import java.awt.geom.AffineTransform;
17 import java.awt.geom.Rectangle2D;
19 import org.simantics.g2d.canvas.Hints;
20 import org.simantics.g2d.canvas.ICanvasContext;
21 import org.simantics.g2d.canvas.SGDesignation;
22 import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;
23 import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency;
24 import org.simantics.g2d.canvas.impl.HintReflection.HintListener;
25 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup;
26 import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;
27 import org.simantics.g2d.utils.GeometryUtils;
28 import org.simantics.scenegraph.g2d.G2DParentNode;
29 import org.simantics.scenegraph.g2d.nodes.BoundsNode;
30 import org.simantics.utils.datastructures.hints.IHintContext;
31 import org.simantics.utils.datastructures.hints.IHintObservable;
32 import org.simantics.utils.datastructures.hints.IHintContext.Key;
35 * A canvas participant that stores the current control and canvas boundaries
36 * and detects their changes.
38 * @author Tuukka Lehtonen
40 public class CanvasBoundsParticipant extends AbstractCanvasParticipant {
42 BoundsNode.ResizeListener resizeListener = new BoundsNode.ResizeListener() {
44 public void controlResized(Rectangle2D bounds) {
45 controlBoundsUpdated(bounds);
50 private TransformUtil util;
52 private BoundsNode boundsNode = null;
54 private Rectangle2D controlBounds = new Rectangle2D.Double();
56 private Rectangle2D canvasBounds = new Rectangle2D.Double();
58 @HintListener(Class=Hints.class, Field="KEY_CANVAS_TRANSFORM")
59 public void selectionChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {
60 // Update canvas bounds whenever canvas transform changes.
61 AffineTransform inv = util.getInverseTransform((AffineTransform) newValue);
63 canvasTransformUpdated(controlBounds, inv);
65 // TODO: what should be done here? Leave canvas bounds as they are or mark them invalid somehow ??
70 public void addedToContext(ICanvasContext ctx) {
71 super.addedToContext(ctx);
72 IHintContext hctx = ctx.getDefaultHintContext();
73 hctx.setHint(Hints.KEY_CONTROL_BOUNDS, controlBounds);
74 hctx.setHint(Hints.KEY_CANVAS_BOUNDS, canvasBounds);
77 @SGInit(designation = SGDesignation.CONTROL)
78 public void initSG(G2DParentNode parent) {
79 boundsNode = parent.addNode("canvasBounds", BoundsNode.class);
80 boundsNode.setZIndex(Integer.MIN_VALUE);
81 boundsNode.setResizeListener(resizeListener);
85 public void cleanupSG() {
86 if (boundsNode != null) {
87 boundsNode.setResizeListener(null);
93 private void controlBoundsUpdated(Rectangle2D bounds) {
94 if (!controlBounds.equals(bounds)) {
95 setControlBounds(bounds.getBounds());
97 AffineTransform invTr = util.getInverseTransform();
99 canvasTransformUpdated(controlBounds, invTr);
102 private void canvasTransformUpdated(Rectangle2D controlBounds, AffineTransform inverseViewTr) {
103 Shape shape = GeometryUtils.transformShape(controlBounds, inverseViewTr);
104 Rectangle2D visibleCanvasBounds = shape.getBounds2D();
105 if (!canvasBounds.equals(visibleCanvasBounds)) {
106 setCanvasBounds(visibleCanvasBounds);
110 private void setControlBounds(Rectangle bounds) {
111 //System.out.println("Set control bounds: " + bounds);
112 this.controlBounds = bounds;
113 IHintContext ctx = getContext().getDefaultHintContext();
114 ctx.setHint(Hints.KEY_CONTROL_BOUNDS, controlBounds);
117 private void setCanvasBounds(Rectangle2D bounds) {
118 //System.out.println("Set canvas bounds: " + bounds);
119 this.canvasBounds = bounds;
120 IHintContext ctx = getContext().getDefaultHintContext();
121 ctx.setHint(Hints.KEY_CANVAS_BOUNDS, canvasBounds);
125 * @return control bounds. Returns internal state, do not modify.
126 * If the current rendering surface is pixel based, the returned
127 * {@link Rectangle2D} may also be a {@link Rectangle}.
129 public Rectangle2D getControlBounds() {
130 return controlBounds;
134 * @return visible canvas area bounds in canvas space coordinates. Returns
135 * internal state, do not modify.
137 public Rectangle2D getCanvasBounds() {