org.piccolo2d.examples.GroupExample Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2011, Piccolo2D project, http://piccolo2d.org
* Copyright (c) 1998-2008, University of Maryland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
* contributors may be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.piccolo2d.examples;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.util.ArrayList;
import org.piccolo2d.PCamera;
import org.piccolo2d.PCanvas;
import org.piccolo2d.PNode;
import org.piccolo2d.extras.PFrame;
import org.piccolo2d.extras.event.PSelectionEventHandler;
import org.piccolo2d.nodes.PPath;
import org.piccolo2d.util.PBounds;
import org.piccolo2d.util.PPaintContext;
/**
* An example of how to implement decorator groups. Decorator groups are nodes
* that base their bounds and rendering on their children. This seems to be a
* common type of visual node that requires some potentially non-obvious
* subclassing to get right.
*
* Both a volatile and a non-volatile implementation are shown. The volatile
* implementation might be used in cases where you want to keep a
* scale-independent pen width border around a group of objects. The
* non-volatile implementation can be used in more standard cases where the
* decorator's bounds are stable during zooming.
*
* @author Lance Good
*/
public class GroupExample extends PFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
public GroupExample() {
this(null);
}
public GroupExample(final PCanvas aCanvas) {
super("GroupExample", false, aCanvas);
}
public void initialize() {
super.initialize();
getCanvas().removeInputEventListener(getCanvas().getPanEventHandler());
// Create a decorator group that is NOT volatile
final DecoratorGroup dg = new DecoratorGroup();
dg.setPaint(Color.magenta);
// Put some nodes under the group for it to decorate
final PPath p1 = PPath.createEllipse(25, 25, 75, 75);
p1.setPaint(Color.red);
final PPath p2 = PPath.createRectangle(125, 75, 50, 50);
p2.setPaint(Color.blue);
// Add everything to the Piccolo hierarchy
dg.addChild(p1);
dg.addChild(p2);
getCanvas().getLayer().addChild(dg);
// Create a decorator group that IS volatile
final VolatileDecoratorGroup vdg = new VolatileDecoratorGroup(getCanvas().getCamera());
vdg.setPaint(Color.cyan);
// Put some nodes under the group for it to decorate
final PPath p3 = PPath.createEllipse(275, 175, 50, 50);
p3.setPaint(Color.blue);
final PPath p4 = PPath.createRectangle(175, 175, 75, 75);
p4.setPaint(Color.green);
// Add everything to the Piccolo hierarchy
vdg.addChild(p3);
vdg.addChild(p4);
getCanvas().getLayer().addChild(vdg);
// Create a selection handler so we can see that the decorator actually
// works
final ArrayList selectableParents = new ArrayList();
selectableParents.add(dg);
selectableParents.add(vdg);
final PSelectionEventHandler ps = new PSelectionEventHandler(getCanvas().getLayer(), selectableParents);
getCanvas().addInputEventListener(ps);
}
public static void main(final String[] args) {
new GroupExample();
}
}
/**
* This is the non-volatile implementation of a decorator group that paints a
* background rectangle based on the bounds of its children.
*/
class DecoratorGroup extends PNode {
/**
*
*/
private static final long serialVersionUID = 1L;
int INDENT = 10;
PBounds cachedChildBounds = new PBounds();
PBounds comparisonBounds = new PBounds();
public DecoratorGroup() {
super();
}
/**
* Change the default paint to fill an expanded bounding box based on its
* children's bounds
*/
public void paint(final PPaintContext ppc) {
final Paint paint = getPaint();
if (paint != null) {
final Graphics2D g2 = ppc.getGraphics();
g2.setPaint(paint);
final PBounds bounds = getUnionOfChildrenBounds(null);
bounds.setRect(bounds.getX() - INDENT, bounds.getY() - INDENT, bounds.getWidth() + 2 * INDENT, bounds
.getHeight()
+ 2 * INDENT);
g2.fill(bounds);
}
}
/**
* Change the full bounds computation to take into account that we are
* expanding the children's bounds Do this instead of overriding
* getBoundsReference() since the node is not volatile
*/
public PBounds computeFullBounds(final PBounds dstBounds) {
final PBounds result = getUnionOfChildrenBounds(dstBounds);
cachedChildBounds.setRect(result);
result.setRect(result.getX() - INDENT, result.getY() - INDENT, result.getWidth() + 2 * INDENT, result
.getHeight()
+ 2 * INDENT);
localToParent(result);
return result;
}
/**
* This is a crucial step. We have to override this method to invalidate the
* paint each time the bounds are changed so we repaint the correct region
*/
public boolean validateFullBounds() {
comparisonBounds = getUnionOfChildrenBounds(comparisonBounds);
if (!cachedChildBounds.equals(comparisonBounds)) {
setPaintInvalid(true);
}
return super.validateFullBounds();
}
}
/**
* This is the volatile implementation of a decorator group that paints a
* background rectangle based on the bounds of its children.
*/
class VolatileDecoratorGroup extends PNode {
/**
*
*/
private static final long serialVersionUID = 1L;
int INDENT = 10;
PBounds cachedChildBounds = new PBounds();
PBounds comparisonBounds = new PBounds();
PCamera renderCamera;
public VolatileDecoratorGroup(final PCamera camera) {
super();
renderCamera = camera;
}
/**
* Indicate that the bounds are volatile for this group
*/
public boolean getBoundsVolatile() {
return true;
}
/**
* Since our bounds are volatile, we can override this method to indicate
* that we are expanding our bounds beyond our children
*/
public PBounds getBoundsReference() {
final PBounds bds = super.getBoundsReference();
getUnionOfChildrenBounds(bds);
cachedChildBounds.setRect(bds);
final double scaledIndent = INDENT / renderCamera.getViewScale();
bds.setRect(bds.getX() - scaledIndent, bds.getY() - scaledIndent, bds.getWidth() + 2 * scaledIndent, bds
.getHeight()
+ 2 * scaledIndent);
return bds;
}
/**
* This is a crucial step. We have to override this method to invalidate the
* paint each time the bounds are changed so we repaint the correct region
*/
public boolean validateFullBounds() {
comparisonBounds = getUnionOfChildrenBounds(comparisonBounds);
if (!cachedChildBounds.equals(comparisonBounds)) {
setPaintInvalid(true);
}
return super.validateFullBounds();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy