import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
/****
*
* Class DrawingCanvas defines a drawing canvas as a JPanel with a specialized
* paint method. See the Java tutorial sections on the
* overview of custom painting and Java 2D
* rendering for the basics of how to specialize the paintComponent method
* for drawing.
*
* @author Gene Fisher (gfisher@calpoly.edu)
* @version 18may10
*
*/
public class DrawingCanvas extends JPanel {
/** Reference to the WorkSpace model, sent in from above */
private WorkSpace workSpace;
/**
* The java draing area.
*/
private Graphics2D g2;
/** The starting x-axis position for drawing a shape */
private int startX;
/** The starting y-axis position for drawing a shape */
private int startY;
/** Quadrant-I normalized value of startY */
private int nStartY;
/** True if the user is moving the mouse. */
private boolean moving = false;
ClickListener clicker;
SelectingMovingListener selectorMover;
LineDrawingListener lineDrawer;
RectDrawingListener rectDrawer;
EllipseDrawingListener ellipseDrawer;
PolyDrawingListener polyDrawer;
TextDrawingListener textDrawer;
MouseInputAdapter currentListener;
DrawingToolBar toolBar;
/**
* Construct this with the given shape list model.
*/
DrawingCanvas(WorkSpace workSpace, DrawingToolBar toolBar) {
/*
* Initialize the model reference.
*/
this.workSpace = workSpace;
this.toolBar = toolBar;
clicker = new ClickListener();
currentListener = clicker;
addMouseListener(clicker);
addMouseMotionListener(clicker);
selectorMover = new SelectingMovingListener(this, workSpace);
lineDrawer = new LineDrawingListener(this, workSpace);
rectDrawer = new RectDrawingListener(this, workSpace);
ellipseDrawer = new EllipseDrawingListener(this, workSpace);
polyDrawer = new PolyDrawingListener(this, workSpace);
textDrawer = new TextDrawingListener(this, workSpace);
setBackground(Color.RED);
setLayout(null);
// setLayoutManager(new CardLayout());
}
public void setListener(String toolName) {
if (toolName == null) {
return;
}
if (toolName == "Select") {
replaceListener(selectorMover);
// System.out.println("Select Tool");
}
if (toolName == "Line") {
// System.out.println("Line Tool");
replaceListener(lineDrawer);
}
else if (toolName == "Rectangle") {
// System.out.println("Rectangle Tool");
replaceListener(rectDrawer);
}
else if (toolName == "Ellipse") {
// System.out.println("Ellipse Tool");
replaceListener(ellipseDrawer);
}
else if (toolName == "Polygon") {
// System.out.println("Polygon Tool");
replaceListener(polyDrawer);
}
else if (toolName == "Text") {
// System.out.println("Text Tool");
// System.out.println("listener count=" + fuck.getMouseListeners().length);
replaceListener(textDrawer);
}
}
public class ClickListener extends MouseInputAdapter {
public void mousePressed(MouseEvent e) {
String selected = toolBar.getSelected();
// System.out.println("selected=" + selected);
if (selected == null) {
return;
}
if (selected == "Select") {
//
}
else if (selected == "Rectangle") {
// System.out.println("Rect selected");
replaceListener(rectDrawer);
processMouseEvent(e);
}
else if (selected == "Ellipse") {
// System.out.println("Ellipse selected");
replaceListener(ellipseDrawer);
processMouseEvent(e);
}
}
}
/**
* Remove the current mouse and mouse motion listerner, then add the given
* listener as the current.
*/
private void replaceListener(MouseInputAdapter listener) {
if (currentListener != null) {
removeMouseListener(currentListener);
removeMouseMotionListener(currentListener);
}
addMouseListener(listener);
addMouseMotionListener(listener);
currentListener = listener;
}
/**
* Draw a base rectangle and each rectangle in parent.workSpace. Model
* rectangles are added to the workSpace by pressing the "Add Rect"
* button in the top-level view.
*/
public void paintComponent(Graphics g) {
/*
* Call the parent JPanel paintComponent to paint the background.
*/
super.paintComponent(g);
/*
* Cast the incoming Graphics object to a Graphics2D. This is the
* standard way to do things.
*/
g2 = (Graphics2D) g;
/*
* Turn anti-aliasing on
*/
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
/*
* Draw the shapes in the work space.
*/
for (int i = 0; i < workSpace.size(); i++) {
Shape shape = workSpace.get(i);
if (shape instanceof Line) {
drawLine((Line)shape);
}
else if (shape instanceof Rectangle) {
drawRectangle((Rectangle)shape);
}
else if (shape instanceof Ellipse) {
drawEllipse((Ellipse)shape);
}
else if (shape instanceof ConvexPolygon) {
drawConvexPolygon((ConvexPolygon)shape);
}
else if (shape instanceof Text) {
drawText((Text)shape);
}
/*
* Return the default color to black, in case it was set in one of
* the drawing methods.
*/
g2.setColor(Color.BLACK);
}
}
private void drawLine(Line l) {
int nx1; // normalized x coord (same as unnormalized)
int ny1; // normalized y coord
int nx2; // normalized x coord (same as unnormalized)
int ny2; // normalized y coord
int ch; // canvas height, for normalization
/*
* Get l's coordinates, normalizing the y's.
*/
ch = getHeight();
nx1 = l.p1.x;
ny1 = ch - l.p1.y;
nx2 = l.p2.x;
ny2 = ch - l.p2.y;
/*
* Draw l; note that the fill does not apply to a line.
*/
g2.setColor(l.getColor());
g2.drawLine(nx1, ny1, nx2, ny2);
if ((! moving) && l.selected) {
drawHandles(nx1, ny1, nx2 - nx1, ny2 - ny1);
}
}
private void drawRectangle(Rectangle r) {
int nx; // normalized x coord (same as unnormalized)
int ny; // normalized y coord
int ch; // canvas height, for normalization
int w; // rectangle width
int h; // rectangle height
/*
* Get r's coordinates, normalizing y.
*/
ch = getHeight();
nx = r.getPosition().x;
ny = ch - r.getPosition().y;
/*
* Get the height and width.
*/
w = (int) r.getWidth();
h = (int) r.getHeight();
/*
* Draw r filled or not filled, as appro.
*/
g2.setColor(r.getColor());
if (r.getFilled()) {
g2.fillRect(nx, ny, w, h);
}
else {
g2.drawRect(nx, ny, w, h);
}
if ((! moving) && r.selected) {
System.out.println(r);
drawHandles(nx, ny, w, h);
}
}
/**
* Model has x,y in center of circle, in quadrant 1. Java wants x,y at
* upper left corner of framing rect, in quadrant 4.
*/
private void drawEllipse(Ellipse e) {
int nx; // normalized x coord (same as unnormalized)
int ny; // normalized y coord
int ch; // canvas height, for normalization
double maj; // semi-major axis
double min; // semi-minor axis
/*
* Normalize qudrants.
*/
ch = getHeight();
nx = e.getPosition().x;
ny = ch - e.getPosition().y;
/*
* Normalize to upper left corner of framing rect.
*/
maj = e.getSemiMajorAxis();
min = e.getSemiMinorAxis();
nx -= maj;
ny -= min;
g2.setColor(e.getColor());
if (e.getFilled()) {
g2.fillOval(nx, ny, (int) (maj * 2), (int) (min * 2));
}
else {
g2.drawOval(nx, ny, (int) (maj * 2), (int) (min * 2));
}
if ((! moving) && e.selected) {
drawHandles(nx, ny, (int) maj * 2, (int) min * 2);
}
}
private void drawConvexPolygon(ConvexPolygon p) {
int ch; // canvas height, for normalization
int n = p.numVertices(); // number of vertices
int[] xs= new int[n]; // array of vertex x coords
int[] nys = new int[n]; // array normalized vertex y coords
/*
* Populate the x/y arrays, normalizing the y coords.
*/
ch = getHeight();
for (int i = 0; i < n; i++) {
xs[i] = p.getVertex(i).x;
nys[i] = ch - p.getVertex(i).y;
}
g2.setColor(p.getColor());
if (p.getFilled()) {
g2.fillPolygon(xs, nys, n);
}
else {
g2.drawPolygon(xs, nys, n);
}
// System.out.println("moving = " + moving + " " + p.selected);
if ((! moving) && p.selected) {
java.awt.Rectangle br =
(new Polygon(xs, nys, n)).getBounds();
drawHandles(br.x, br.y, br.width, br.height);
}
}
private void drawText(Text t) {
int nx; // normalized x coord (same as unnormalized)
int ny; // normalized y coord
int ch; // canvas height, for normalization
String s; // the text string
/*
* Get t's coordinates, normalizing y.
*/
ch = getHeight();
nx = t.x;
ny = ch - t.y;
/*
* Get the string
*/
s = t.s;
/*
* Draw t; unfilled is the only way.
*/
g2.setColor(t.getColor());
g2.drawString(s, nx, ny = t.y + 14);
// System.out.println(g2.getFont().getSize());
if ((! moving) && t.selected) {
Rectangle2D br =
g2.getFont().getStringBounds(s, g2.getFontRenderContext());
drawHandles(nx, t.y, (int) br.getWidth(), (int) br.getHeight());
}
}
/**
* Draw eight 4x4 rectangles on the corners and edge midpoints of the
* rectangle defined by the given x,y,width,height parameters.
*/
private void drawHandles(int nx, int ny, int w, int h) {
/*
* Debug by setting handles to different colors.
*/
int lbx = nx - 2;
int lby = ny + h - 2;
g2.setColor(Color.BLACK); // RED);
g2.fillRect(lbx, lby, 4, 4);
int bx = nx + w/2 - 2;
int by = lby;
g2.setColor(Color.BLACK); // ORANGE);
g2.fillRect(bx, by, 4, 4);
int rbx = nx + w - 2;
int rby = lby;
g2.setColor(Color.BLACK); // YELLOW);
g2.fillRect(rbx, rby, 4, 4);
int rx = rbx;
int ry = rby - h/2;
g2.setColor(Color.BLACK); // GREEN);
g2.fillRect(rx, ry, 4, 4);
int rtx = rbx;
int rty = rby - h;
g2.setColor(Color.BLACK); // BLUE);
g2.fillRect(rtx, rty, 4, 4);
int tx = rtx - w/2;
int ty = rty;
g2.setColor(Color.BLACK); // MAGENTA);
g2.fillRect(tx, ty, 4, 4);
int ltx = lbx;
int lty = rty;
g2.setColor(Color.BLACK); // GRAY);
g2.fillRect(ltx, lty, 4, 4);
int lx = ltx;
int ly = ry;
g2.setColor(Color.BLACK); // BLACK);
g2.fillRect(lx, ly, 4, 4);
}
private void drawHandlesFucked(Rectangle rect) {
int ch = getHeight();
Point pos = rect.getPosition();
Point lb = rect.getVertex(0);
Point rb = rect.getVertex(1);
Point rt = rect.getVertex(2);
Point lt = rect.getVertex(3);
Point l = new Point(lb.x, ch-lb.y - (ch-lb.y - ch-rb.y) / 2);
Point b = new Point(lb.x + (lb.x - rb.x) / 2, ch-lb.y);
Point r = new Point(rb.x, ch-rb.y + (ch-rt.y - ch-rb.y) / 2);
Point t = new Point(rt.x - (lt.x - rt.x) / 2, ch-rt.y);
int width = lt.y - lt.y;
int half_width = width/2;
int height = lt.y - lb.y;
// System.out.println(lt.x + "," + lt.y + "," + width + "," + height);
Rectangle2D.Double h1 = new Rectangle2D.Double(
lt.x - 2, ch-lt.y - height -3, 6, 6);
Rectangle2D.Double h2 = new Rectangle2D.Double(
l.x - 2, ch-l.y - height -3, 6, 6);
Rectangle2D.Double h3 = new Rectangle2D.Double(
lb.x - 2, ch-lb.y -3, 6, 6);
Rectangle2D.Double h4 = new Rectangle2D.Double(
b.x - 2, ch-b.y -3, 6, 6);
Rectangle2D.Double h5 = new Rectangle2D.Double(
rb.x - 2 , ch-rb.y -3, 6, 6);
Rectangle2D.Double h6 = new Rectangle2D.Double(
r.x - 2, ch-r.y -3, 6, 6);
Rectangle2D.Double h7 = new Rectangle2D.Double(
rt.x - 2, ch-rt.y -3, 6, 6);
Rectangle2D.Double h8 = new Rectangle2D.Double(
t.x - 2, ch-t.y -3, 6, 6);
g2.setColor(Color.BLACK); // RED);
g2.fill(h1);
g2.setColor(Color.BLACK); // ORANGE);
g2.fill(h2);
g2.setColor(Color.BLACK); // YELLOW);
g2.fill(h3);
g2.setColor(Color.BLACK); // GREEN);
g2.fill(h4);
g2.setColor(Color.BLACK); // BLUE);
g2.fill(h5);
g2.setColor(Color.BLACK); // MAGENTA);
g2.fill(h6);
g2.setColor(Color.BLACK); // GRAY);
g2.fill(h7);
g2.setColor(Color.BLACK); // BLACK);
g2.fill(h8);
}
}