package trident.swing;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import org.pushingpixels.trident.Timeline;
import org.pushingpixels.trident.Timeline.RepeatBehavior;
import org.pushingpixels.trident.Timeline.TimelineState;
import org.pushingpixels.trident.callback.TimelineCallbackAdapter;
import org.pushingpixels.trident.swing.SwingRepaintTimeline;
public class ShapesFrame extends JFrame {
public static final Color COLOR_BLUE = new Color(128, 128, 255);
public static final Color COLOR_GREEN = new Color(128, 255, 128);
public class ShapesPanel extends JComponent {
private List<MyShape> shapes;
private boolean toAddRectangle;
private Color topColor;
private Color bottomColor;
public ShapesPanel() {
this.shapes = new ArrayList<MyShape>();
this.topColor = COLOR_BLUE;
this.bottomColor = COLOR_GREEN;
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
addShape(e.getPoint());
}
});
// animate the gradient endpoint colors in an infinite timeline
Timeline colorTimeline = new SwingRepaintTimeline(this);
colorTimeline.addPropertyToInterpolate("topColor", COLOR_BLUE,
COLOR_GREEN);
colorTimeline.addPropertyToInterpolate("bottomColor", COLOR_GREEN,
COLOR_BLUE);
colorTimeline.setDuration(1000);
colorTimeline.playLoop(RepeatBehavior.REVERSE);
}
public void setTopColor(Color topColor) {
this.topColor = topColor;
}
public void setBottomColor(Color bottomColor) {
this.bottomColor = bottomColor;
}
public void addShape(MyShape shape) {
synchronized (this.shapes) {
this.shapes.add(shape);
}
}
public void removeShape(MyShape shape) {
synchronized (this.shapes) {
this.shapes.remove(shape);
}
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setPaint(new GradientPaint(0, 0, this.topColor, 0, getHeight(),
this.bottomColor));
g2d.fillRect(0, 0, getWidth(), getHeight());
synchronized (this.shapes) {
for (MyShape shape : this.shapes) {
shape.paint(g2d);
}
}
g2d.dispose();
}
private void addShape(Point point) {
int x = point.x;
int y = point.y;
if (toAddRectangle) {
final MyShape shape = new MyRectangle(x, y, 0, 0);
addShape(shape);
Timeline timelineRectangleFade = new Timeline(shape);
timelineRectangleFade.addPropertyToInterpolate("x", x, x - 100);
timelineRectangleFade.addPropertyToInterpolate("y", y, y - 100);
timelineRectangleFade.addPropertyToInterpolate("width", 0, 200);
timelineRectangleFade
.addPropertyToInterpolate("height", 0, 200);
timelineRectangleFade.addPropertyToInterpolate("rotation", 0,
180);
timelineRectangleFade.addPropertyToInterpolate("opacity", 1.0f,
0.0f);
timelineRectangleFade
.addCallback(new TimelineCallbackAdapter() {
@Override
public void onTimelineStateChanged(
TimelineState oldState,
TimelineState newState,
float durationFraction,
float timelinePosition) {
if (newState == TimelineState.DONE)
removeShape(shape);
}
});
timelineRectangleFade.setDuration(1000);
timelineRectangleFade.play();
} else {
final MyShape shape = new MyCircle(x, y, 0);
addShape(shape);
Timeline timelineCircleFade = new Timeline(shape);
timelineCircleFade.addPropertyToInterpolate("radius", 0, 100);
timelineCircleFade.addPropertyToInterpolate("opacity", 1.0f,
0.0f);
timelineCircleFade.addCallback(new TimelineCallbackAdapter() {
@Override
public void onTimelineStateChanged(TimelineState oldState,
TimelineState newState, float durationFraction,
float timelinePosition) {
if (newState == TimelineState.DONE)
removeShape(shape);
}
});
timelineCircleFade.setDuration(1000);
timelineCircleFade.play();
}
toAddRectangle = !toAddRectangle;
}
}
public interface MyShape {
public void paint(Graphics g);
}
public class MyRectangle implements MyShape {
float x;
float y;
float width;
float height;
float opacity;
float rotation;
public MyRectangle(float x, float y, float width, float height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.opacity = 1.0f;
this.rotation = 0.0f;
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
public void setWidth(float width) {
this.width = width;
}
public void setHeight(float height) {
this.height = height;
}
public void setOpacity(float opacity) {
this.opacity = opacity;
}
public void setRotation(float rotation) {
this.rotation = rotation;
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.SrcOver.derive(this.opacity));
g2d.setColor(COLOR_GREEN);
float xc = this.x + this.width / 2;
float yc = this.y + this.height / 2;
g2d.translate((int) xc, (int) yc);
g2d.rotate(this.rotation * Math.PI / 180.0);
g2d.fill(new Rectangle2D.Float(-this.width / 2, -this.height / 2,
this.width, this.height));
g2d.dispose();
}
}
public class MyCircle implements MyShape {
float x;
float y;
float radius;
float opacity;
public MyCircle(float x, float y, float radius) {
this.x = x;
this.y = y;
this.radius = radius;
this.opacity = 1.0f;
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
public void setRadius(float radius) {
this.radius = radius;
}
public void setOpacity(float opacity) {
this.opacity = opacity;
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.SrcOver.derive(this.opacity));
g2d.setColor(COLOR_GREEN);
g2d.fill(new Ellipse2D.Float(this.x - this.radius, this.y
- this.radius, 2 * radius, 2 * radius));
g2d.dispose();
}
}
public ShapesFrame() {
super("Swing Shapes");
ShapesPanel sPanel = new ShapesPanel();
this.add(sPanel, BorderLayout.CENTER);
this.setSize(600, 500);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ShapesFrame().setVisible(true);
}
});
}
}