/**
* Generic object the SumlCanvas will be able to draw onto the screen. Defines
* the following abstract methods which must be overridden by children:
*
*
* - public void draw (Graphic g)
* - public void move (Point delta)
* - public void scale (double x, double y)
*
*
* @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 simple_uml.view.canvas.SumlCanvas;
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();
/**
* The canvas we're to be painted on.
* @see #simple_uml.view.canvas.SumlCanvas
*/
protected SumlCanvas canvas;
/*<==*/
public SumlShape () { }
/**
* Creates a shape w/ the specified color
*/
public SumlShape (SumlCanvas canvas, Color c)
{
this.canvas = canvas;
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;
}
public Object getModel ()
{
throw new UnsupportedOperationException();
}
/*<==*/
/* 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);
/*<==*/
}