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