/** * Generic object the SumlCanvas will be able to draw onto the screen. Defines * the following abstract methods which must be overridden by children: * * * * @author Eric Liebowitz * @version 22jun11 */ package simple_uml.view.canvas; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.geom.Point2D; import java.util.Stack; import java.util.Vector; public abstract class SumlShape { /* CONSTANTS ==>*/ /** Base x-coord for BASE_ORIGIN */ protected static final int X_BASE = 0; /** Base y-coord for BASE_ORIGIN */ protected static final int Y_BASE = 0; /** Where all shapes are drawn relative to, by default */ protected static final Point BASE_ORIGIN = new Point(X_BASE, Y_BASE); /*<==*/ /* INSTANCE VARIABLES ==>*/ /** * Stores Graphics2D AffineTransforms so that you can save transforms, alter * them, and restore them later. * * @see #pushMatrix(Graphics2D) * @see #popMatrix(Graphics2D) */ private Stack matrixStack = new Stack(); /** * The transform matrix applied to this shape before drawing */ protected AffineTransform tMatrix = new AffineTransform(); /** * The upper-left corner of this shape, where all components of said shape * are drawn relative to. */ protected Point origin = new Point(BASE_ORIGIN); /** * Bounding box of the shape, letting you know the min height/width needed * to fully contain its members. Default is a rect with width/height = 0, * located at point (0, 0). */ protected Rectangle bounds = new Rectangle(X_BASE, Y_BASE, 0, 0); /** * Color the shape should be. Default is Color.black */ protected Color color = Color.black; /** * Whether this shape is selected. Default is false. */ protected boolean selected = false; /** * List of any listeners who like to know when this shape changes */ protected Vector listeners = new Vector(); /*<==*/ public SumlShape () { } /** * Creates a shape w/ the specified color */ public SumlShape (Color c) { this.color = c; } public void addListener (ShapeListener sl) { this.listeners.add(sl); } /* GETTERS ==>*/ /** * Returns the width of this shape, as defined by its bounding box * * @return the width of this shape (default 0) */ public int getWidth () { return (int)this.bounds.getWidth(); } /** * Returns the height of this shape, as defined by its bounding box * * @return the height of this shape (default 0) */ public int getHeight () { return (int)this.bounds.getHeight(); } /** * Returns this shape's origin. * * @return this shape's origin */ public Point getOrigin () { return this.origin; } /*<==*/ /* SETTERS ==>*/ /** * Sets this shape's origin * * @param x x-coord you want the origin to be at * @param y y-coord you want the origin to be at */ public void setOrigin (int x, int y) { this.origin = new Point(x, y); } /*<==*/ /* DRAWING ==>*/ public boolean intersects (Rectangle2D r) { return bounds.intersects(r); } /** * Moves this shape by a given amount. This will translate * the transform matrix by the same amount. * * @param dx Amount in x-direction you wish to move * @param dy Amount in y-direction you wish to move */ public void move (int dx, int dy) { this.tMatrix.translate(dx, dy); tMatrix.transform(BASE_ORIGIN, origin); for (ShapeListener sl: this.listeners) { sl.shapeMoved(); } } /** * Scales this shape by the given percentages. This scales the transform * matrix in order to accomplish the task. * * @param x percentage in x-direction you wish to scale * @param y percentage in y-direction you wish to scale */ public void scale (double x, double y) { this.tMatrix.scale(x, y); } /** * Pushes the Graphics2D transform onto this object's stack of saved * transforms. * * @param g2d Graphics2D to get the current AffineTransform from */ public void pushMatrix (Graphics2D g2d) { this.matrixStack.push(g2d.getTransform()); } /** * Pops a transform off the stack and sets the Graphics2D to have the popped * transform. * * @param g2d Graphics2D which is to have its transform set to the popped * value */ public void popMatrix (Graphics2D g2d) { g2d.setTransform(this.matrixStack.pop()); } /** * Paints the shape on the screen. Outsiders call this method to get things * drawn, as it automatically saved the current g2d transform and applies * this shape's transform matrix. * * @param g2d Graphics2D to do the drawing */ public void paint (Graphics2D g2d) { pushMatrix(g2d); g2d.transform(this.tMatrix); draw(g2d); popMatrix(g2d); } /** * Does the work of actually drawing the shape. * * @param g2d Graphics2D to do the drawing. */ protected abstract void draw (Graphics2D g2d); /*<==*/ }