package edu.umd.cs.piccolo.examples;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import edu.umd.cs.piccolo.PCanvas;
import edu.umd.cs.piccolo.PLayer;
import edu.umd.cs.piccolo.PNode;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PDragEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PImage;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolo.nodes.PText;
import edu.umd.cs.piccolo.util.PBounds;
import edu.umd.cs.piccolo.util.PPaintContext;
import edu.umd.cs.piccolox.PFrame;
/**
* This example shows how to create and manipulate nodes.
*/
public class NodeExample extends PFrame {
boolean fIsPressed = false;
public NodeExample() {
this(null);
}
public NodeExample(PCanvas aCanvas) {
super("NodeExample", false, aCanvas);
}
public void initialize() {
nodeDemo();
createNodeUsingExistingClasses();
subclassExistingClasses();
composeOtherNodes();
createCustomNode();
// Last of all lets remove the default pan event handler, and add a
// drag event handler instead. This way you will be able to drag the
// nodes around with the mouse.
getCanvas().removeInputEventListener(getCanvas().getPanEventHandler());
getCanvas().addInputEventListener(new PDragEventHandler());
}
// This method demonstrates the kinds of things that can be done with any node.
public void nodeDemo() {
PLayer layer = getCanvas().getLayer();
PNode aNode = PPath.createRectangle(0, 0, 100, 80);
// A node needs to be a descendent of the root to be displayed on the screen.
layer.addChild(aNode);
// The default color for a node is blue, but you can change that with
// the setPaint method.
aNode.setPaint(Color.red);
// A node can have children nodes added to it.
aNode.addChild(PPath.createRectangle(0, 0, 100, 80));
// The base bounds of a node is easy to change. Note that changing the base
// bounds of a node will not change it's children.
aNode.setBounds(-10, -10, 200, 110);
// Each node has a transform that can be used to transform the node, and
// all its children on the screen.
aNode.translate(100, 100);
aNode.scale(1.5);
aNode.rotate(45);
// The transparency of any node can be set, this transparency will be
// applied to any of the nodes children as well.
aNode.setTransparency(0.75f);
// Its easy to copy nodes.
PNode aCopy = (PNode) aNode.clone();
// Make is so that the copies children are not pickable. For this example
// that means you will not be able to grab the child and remove it from
// its parent.
aNode.setChildrenPickable(false);
// Change the look of the copy
aNode.setPaint(Color.GREEN);
aNode.setTransparency(1.0f);
// Let's add the copy to the root, and translate it so that it does not
// cover the original node.
layer.addChild(aCopy);
aCopy.setOffset(0, 0);
aCopy.rotate(-45);
}
// So far we have just been using PNode, but of course PNode has many
// subclasses that you can try out to.
public void createNodeUsingExistingClasses() {
PLayer layer = getCanvas().getLayer();
layer.addChild(PPath.createEllipse(0, 0, 100, 100));
layer.addChild(PPath.createRectangle(0, 100, 100, 100));
layer.addChild(new PText("Hello World"));
// Here we create an image node that displays a thumbnail
// image of the root node. Note that you can easily get a thumbnail
// of any node by using PNode.toImage().
PImage image = new PImage(layer.toImage(300, 300, null));
layer.addChild(image);
}
// Another way to create nodes is to customize other nodes that already
// exist. Here we create an ellipse, except when you press the mouse on
// this ellipse it turns into a square, when you release the mouse it
// goes back to being an ellipse.
public void subclassExistingClasses() {
final PNode n = new PPath(new Ellipse2D.Float(0, 0, 100, 80)) {
public void paint(PPaintContext aPaintContext) {
if (fIsPressed) {
// if mouse is pressed draw self as a square.
Graphics2D g2 = aPaintContext.getGraphics();
g2.setPaint(getPaint());
g2.fill(getBoundsReference());
} else {
// if mouse is not pressed draw self normally.
super.paint(aPaintContext);
}
}
};
n.addInputEventListener(new PBasicInputEventHandler() {
public void mousePressed(PInputEvent aEvent) {
super.mousePressed(aEvent);
fIsPressed = true;
n.invalidatePaint(); // this tells the framework that the node needs to be redisplayed.
}
public void mouseReleased(PInputEvent aEvent) {
super.mousePressed(aEvent);
fIsPressed = false;
n.invalidatePaint(); // this tells the framework that the node needs to be redisplayed.
}
});
n.setPaint(Color.ORANGE);
getCanvas().getLayer().addChild(n);
}
// Here a new "face" node is created. But instead of drawing the face directly
// using Graphics2D we compose the face from other nodes.
public void composeOtherNodes() {
PNode myCompositeFace = PPath.createRectangle(0, 0, 100, 80);
// create parts for the face.
PNode eye1 = PPath.createEllipse(0, 0, 20, 20);
eye1.setPaint(Color.YELLOW);
PNode eye2 = (PNode) eye1.clone();
PNode mouth = PPath.createRectangle(0, 0, 40, 20);
mouth.setPaint(Color.BLACK);
// add the face parts
myCompositeFace.addChild(eye1);
myCompositeFace.addChild(eye2);
myCompositeFace.addChild(mouth);
// don't want anyone grabbing out our eye's.
myCompositeFace.setChildrenPickable(false);
// position the face parts.
eye2.translate(25, 0);
mouth.translate(0, 30);
// set the face bounds so that it neatly contains the face parts.
PBounds b = myCompositeFace.getUnionOfChildrenBounds(null);
myCompositeFace.setBounds(b.inset(-5, -5));
// opps it to small, so scale it up.
myCompositeFace.scale(1.5);
getCanvas().getLayer().addChild(myCompositeFace);
}
// Here a completely new kind of node, a grid node" is created. We do
// all the drawing ourselves here instead of passing the work off to
// other parts of the framework.
public void createCustomNode() {
PNode n = new PNode() {
public void paint(PPaintContext aPaintContext) {
double bx = getX();
double by = getY();
double rightBorder = bx + getWidth();
double bottomBorder = by + getHeight();
Line2D line = new Line2D.Double();
Graphics2D g2 = aPaintContext.getGraphics();
g2.setStroke(new BasicStroke(0));
g2.setPaint(getPaint());
// draw vertical lines
for (double x = bx; x < rightBorder; x += 5) {
line.setLine(x, by, x, bottomBorder);
g2.draw(line);
}
for (double y = by; y < bottomBorder; y += 5) {
line.setLine(bx, y, rightBorder, y);
g2.draw(line);
}
}
};
n.setBounds(0, 0, 100, 80);
n.setPaint(Color.black);
getCanvas().getLayer().addChild(n);
}
public static void main(String[] args) {
new NodeExample();
}
}