// Copyright MageLang Institute; Version $Id: //depot/main/src/edu/modules/Beans/magercises/StickFigureCustomizer/Solution/stickfigure/StickFigure.java#5 $ package stickfigure; import java.awt.*; import java.beans.*; import java.util.*; public class StickFigure extends Component { private static final int MIN_SIZE = 16; private static final int MAX_SIZE = 512; private static final int DEFAULT_SIZE = 64; public static final int HAPPY = -1; public static final int SAD = -2; public static final int AMBIVALENT = -3; public static final String HAPPY_STR = "Happy"; public static final String SAD_STR = "Sad"; public static final String AMBIVALENT_STR = "Ambivalent"; private int mood = HAPPY; private boolean hasNeck = true; private boolean hasTrunk = true; private boolean hasLeftArm = true; private boolean hasRightArm = true; private boolean hasLeftLeg = true; private boolean hasRightLeg = true; private boolean hasSunburn = false; private boolean surprised = false; private Color normalColor; private Vector targets = new Vector(); private PropertyChangeSupport changes = new PropertyChangeSupport(this); public StickFigure() { normalColor = getForeground(); } public synchronized void addStickFigureListener(StickFigureListener l) { targets.addElement(l); } public synchronized void removeStickFigureListener(StickFigureListener l) { targets.removeElement(l); } protected void notifyTargets() { Vector l; StickFigureEvent s = new StickFigureEvent(this); synchronized(this) { l = (Vector) targets.clone(); } for (int i = 0; i < l.size(); i++) { StickFigureListener sl = (StickFigureListener) l.elementAt(i); sl.stickFigureChanged(s); } } public void addPropertyChangeListener( PropertyChangeListener p) { changes.addPropertyChangeListener(p); } public void removePropertyChangeListener( PropertyChangeListener p) { changes.removePropertyChangeListener(p); } public synchronized void setSunburned(boolean state) { if (!hasSunburn) normalColor = getForeground(); hasSunburn = state; Color old = getForeground(); if (hasSunburn) setForeground(Color.red); else setForeground(normalColor); repaint(); changes.firePropertyChange("sunburned", old, getForeground()); } public boolean isSunburned() { return hasSunburn; } public synchronized void setNeck(boolean state) { hasNeck = state; refreshAndNotify(); } public boolean getNeck() { return hasNeck; } public synchronized void setTrunk(boolean state) { hasTrunk = state; refreshAndNotify(); } public boolean getTrunk() { return hasTrunk; } public synchronized void setLeftArm(boolean state) { hasLeftArm = state; refreshAndNotify(); } public boolean getLeftArm() { return hasLeftArm; } public synchronized void setRightArm(boolean state) { hasRightArm = state; refreshAndNotify(); } public boolean getRightArm() { return hasRightArm; } public synchronized void setLeftLeg(boolean state) { hasLeftLeg = state; refreshAndNotify(); } public boolean getLeftLeg() { return hasLeftLeg; } public synchronized void setRightLeg(boolean state) { hasRightLeg = state; refreshAndNotify(); } public boolean getRightLeg() { return hasRightLeg; } public synchronized void setMood(int mood) { int old = this.mood; this.mood = mood; repaint(); changes.firePropertyChange("mood", new Integer(old), new Integer(mood)); } public int getMood() { return mood; } public synchronized void addSurprise() { surprised = true; repaint(); } public synchronized void removeSurprise() { surprised = false; repaint(); } private void refreshAndNotify() { repaint(); notifyTargets(); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { g.setColor(getBackground()); g.fillRect(0, 0, getSize().width - 1, getSize().height - 1); g.setColor(getForeground()); drawHead(g); drawMouth(g); drawNeck(g); drawLeftArm(g); drawRightArm(g); drawTrunk(g); drawLeftLeg(g); drawRightLeg(g); } private void drawHead(Graphics g) { g.drawArc( (getSize().width - getHeadSize()) / 2, getHeadTop(), getHeadSize(), getHeadSize(), 0, 360); } private void drawNeck(Graphics g) { if (!getNeck()) return; g.drawLine(getMidLine(), getNeckTop(), getMidLine(), getArmTop()); } private void drawTrunk(Graphics g) { if (!getTrunk()) return; g.drawLine(getMidLine(), getArmTop(), getMidLine(), getLegTop()); } private void drawLeftArm(Graphics g) { if (!getLeftArm()) return; g.drawLine(getMidLine(), getArmTop(), (getMidLine()) + getArmHOffset(), getArmBottom()); } private void drawRightArm(Graphics g) { if (!getRightArm()) return; g.drawLine(getMidLine(), getArmTop(), (getMidLine()) - getArmHOffset(), getArmBottom()); } private void drawLeftLeg(Graphics g) { if (!getLeftLeg()) return; g.drawLine(getMidLine(), getLegTop(), (getMidLine()) + getLegHOffset(), getLegBottom()); } private void drawRightLeg(Graphics g) { if (!getRightLeg()) return; g.drawLine(getMidLine(), getLegTop(), (getMidLine()) - getLegHOffset(), getLegBottom()); } private void drawMouth(Graphics g) { if (surprised) drawSurprise(g); else { if (mood == HAPPY) g.drawArc( (getSize().width - getHeadSize()) / 2, getHeadTop() - (getHeadSize() / 5), getHeadSize(), getHeadSize(), 240, 60); else if (mood == SAD) g.drawArc( (getSize().width - getHeadSize()) / 2, getNeckTop() - (getHeadSize() / 4), getHeadSize(), getHeadSize(), 60, 60); else g.drawLine( getMidLine() - (getHeadSize() / 7), getNeckTop() - (getHeadSize() / 5), getMidLine() + (getHeadSize() / 7), getNeckTop() - (getHeadSize() / 5)); } } private void drawSurprise(Graphics g) { if (!surprised) return; g.drawArc( (getSize().width - getMouthSize()) / 2, getNeckTop() - (getHeadSize() / 2), getMouthSize(), (getMouthSize() * 125) / 100, 0, 360); } private int getHeadSize() { return Math.min(getSize().width, getSize().height) / 5; } private int getMouthSize() { int size = getHeadSize() / 3; return size > 0 ? size : 3; } private int getNeckSize() { return hasNeck ? getHeadSize() / 3 : 0; } private int getTrunkSize() { return hasTrunk ? (getHeadSize() * 3) / 2 : 0; } private int getMidLine() { return getSize().width / 2; } private int getArmHOffset() { return getHeadSize(); } private int getLegHOffset() { return getHeadSize() / 2; } private int getHeadTop() { return (getSize().height - (getHeadSize() + getNeckSize() + getTrunkSize() + getLegVDistance() ) ) / 2; } private int getNeckTop() { return getHeadTop() + getHeadSize(); } private int getArmTop() { return getNeckTop() + getNeckSize(); } private int getArmBottom() { return getArmTop() + (getHeadSize() * 3) / 2; } private int getLegTop() { return getArmTop() + getTrunkSize(); } private int getLegBottom() { return getLegTop() + getLegVDistance(); } private int getLegVDistance() { return (getHeadSize() * 3) / 2; } public Dimension getMinimumSize() { return new Dimension(MIN_SIZE, MIN_SIZE); } public Dimension getMaximumSize() { return new Dimension(MAX_SIZE, MAX_SIZE); } public Dimension getPreferredSize() { return new Dimension(DEFAULT_SIZE, DEFAULT_SIZE); } }