import java.awt.*; import java.applet.*; import java.awt.event.*; /** * OCC - CS 170 Homework 12 Starter file * Displays pictures and lets users draw on pictures * @author Stephen Gilbert * @version 2, Jan 2, 2002 */ public class Scrawler extends Applet implements ItemListener, MouseMotionListener, MouseListener { // theImage -> image loaded from file private Image theImage = null; // offscreen image and graphics context private Image offImage = null; private Graphics og = null; // Choice contains the names of image files private Choice theImgFile = new Choice(); // Fields used to control the drawing private int xPos, yPos, newX, newY; private int drawMode = 1; private int penWidth = 4; private Color penColor = Color.red; // Fields for the top toolbar private Panel topBar = new Panel(new FlowLayout(FlowLayout.LEFT)); // Fields for the bottom toolbar private Panel bottomBar = new Panel(new FlowLayout(FlowLayout.LEFT)); // Fields for the side toolbar private Panel sideBar = new Panel(new GridLayout(1,1)); /** -------------------------------------------------------- * init() method * Change the layout, set background color * Add file names to Choice, add ItemListener * Add MouseListener and MouseMotionLister to applet */ public void init() { setLayout(new BorderLayout()); setBackground(Color.yellow); add(bottomBar, BorderLayout.SOUTH); add(topBar, BorderLayout.NORTH); add(sideBar, BorderLayout.EAST); bottomBar.add(theImgFile); theImgFile.add("Select an Image"); theImgFile.add("beach.jpg"); theImgFile.add("office.jpg"); theImgFile.add("christmas.jpg"); theImgFile.select(0); theImgFile.addItemListener(this); addMouseListener(this); addMouseMotionListener(this); } /** -------------------------------------------------------- * update(Graphics g) * Calls paint() without erasing * * paint(Graphics g) * Draws the offImage, if it is not null * --------------------------------------------------------- */ public void update(Graphics g) { paint(g); } public void paint(Graphics g) { int w = getSize().width - sideBar.getSize().width; int h = getSize().height - ( topBar.getSize().height + bottomBar.getSize().height); g.translate(0, topBar.getSize().height); if (offImage != null) { g.drawImage(offImage, 0, 0, w, h, this); } } /** -------------------------------------------------------- * Event handler for the Choice containing names of files * Calls private loadImage() method if selected item is * not the first item on the list. * -------------------------------------------------------- */ public void itemStateChanged(ItemEvent ev) { if (theImgFile.getSelectedIndex() > 0) loadImage(theImgFile.getSelectedItem()); } /** -------------------------------------------------------- * Loads image from file and initializes offscreen buffer * @param name name of the file to be loaded * -------------------------------------------------------- */ private void loadImage(String name) { showStatus("Loading image: " + name); theImage = getImage(getDocumentBase(), name); MediaTracker mt = new MediaTracker(this); mt.addImage(theImage, 0); try { mt.waitForAll(); } catch (InterruptedException ie) { } if (theImage == null) { showStatus("Could not locate or load " + name); return; } // Crete the offscreen image if file loaded OK int w = getSize().width; int h = getSize().height; offImage = createImage(w, h); og = offImage.getGraphics(); og.drawImage(theImage,0,0,w,h,this); repaint(); } /** -------------------------------------------------------- * mousePressed(), mouseDragged(), and mouseReleased() * (Java 1.1 event handling) * 1. Mouse down sets xPos, yPos, newX, newY to mouse pos * 2. Mouse drag draws a freehand line or rubberband * 3. Mouse up draws a finished line or shape */ public void mousePressed(MouseEvent me) { xPos = newX = me.getX(); yPos = newY = me.getY(); } // * -------------------------------------------- public void mouseDragged(MouseEvent me) { // 1. Set up the Graphics drawing context if (og == null) return; // If drawMode > 1 then rubber band if (drawMode > 1) rubberBand(me.getX(), me.getY()); else // Drawing freehand { // Set the penColor og.setColor(penColor); if (penWidth == 1) og.drawLine(xPos, yPos, me.getX(), me.getY()); else { newX = me.getX(); newY = me.getY(); drawALine(); } xPos = me.getX(); yPos = me.getY(); } } // *------------------------------------------ public void mouseReleased(MouseEvent me) { if (og == null) return; if (drawMode > 1) { if (drawMode == 2) drawALine(); else drawAShape(); xPos = newX = me.getX(); yPos = newY = me.getY(); } } /** -------------------------------------------------------- * Drawing methods for lines and shapes * 1. rubberBand(int x, int y) * 2. drawALine() * 3. drawAShape() * -------------------------------------------------------- * rubberBand(int x, int y) * Draws both rubber-banded lines and rubber-banded shapes * @param x new horizontal ending point * @param y new vertical ending point * -------------------------------------------------------- */ public void rubberBand(int x, int y) { // 1. Set the painting mode to XOR Graphics g = getGraphics(); g.setXORMode(getBackground()); // 2. Draw the old line or shape between xPos, yPos and // newX, newY. Once that's drawn, set newX == X and // newY == y and do it again in the new position for (int i = 0; i < 2; i++) { if (drawMode == 2) g.drawLine(xPos, yPos, newX, newY); else { g.drawRect(Math.min(xPos, newX), Math.min(yPos, newY), Math.abs(xPos-newX), Math.abs(yPos-newY)); } newX = x; newY = y; } g.dispose(); } /** -------------------------------------------------------- * drawALine() * Draws a colored line from xPos, yPos to newX, newY, * using penColor and penWidth * A modification of Breshenham's algorithm * Uses private methodd Sign() * -------------------------------------------------------- */ private int Sign(int a) { if (a < 0 ) return -1; if (a == 0) return 0; return 1; } private void drawALine() { int dx = Math.abs(xPos - newX); int dy = Math.abs(yPos - newY); int sx = Sign(newX - xPos); int sy = Sign(newY - yPos); int x = xPos; int y = yPos; boolean interchange; if (dy > dx) { int temp = dx; dx = dy; dy = temp; interchange = true; } else interchange = false; int p = 2 * dy + dx; Graphics g = getGraphics(); g.setColor(penColor); og.setColor(penColor); g.fillOval(x-penWidth/2, y-penWidth/2, penWidth, penWidth); og.fillOval(x-penWidth/2, y-penWidth/2, penWidth, penWidth); for (int i = 1; i <= dx; i++ ) { while (p >= 0) { if (interchange) x = x + sx; else y = y + sy; p = p - 2 * dx; } if (interchange) y = y + sy; else x = x + sx; p = p + 2 * dy; g.fillOval(x-penWidth/2, y-penWidth/2, penWidth, penWidth); og.fillOval(x-penWidth/2, y-penWidth/2, penWidth, penWidth); } g.dispose(); } /** -------------------------------------------------------- * drawAShape() * Draws rectangles, ovals, filled rectangles and * filled ovals. * -------------------------------------------------------- */ public void drawAShape() { // 1. "Normalize" the 4 corners of the bounding rectangle int temp; if (xPos > newX) { temp = xPos; xPos = newX; newX = temp; } if (yPos > newY) { temp = yPos; yPos = newY; newY = temp; } // 2. Erase the last rubber-banding rectangle Graphics g = getGraphics(); g.setXORMode(getBackground()); g.drawRect(xPos, yPos, (newX - xPos), (newY - yPos)); // 3. Set the painting mode to "Paint" and set the pen color g.setPaintMode(); g.setColor(penColor); og.setColor(penColor); // 4. Draw a shape based upon drawMode switch (drawMode) { case 4: g.fillRect(xPos, yPos, newX - xPos, newY - yPos); og.fillRect(xPos, yPos, newX - xPos, newY - yPos); break; case 6: g.fillOval(xPos, yPos, newX - xPos, newY - yPos); og.fillOval(xPos, yPos, newX - xPos, newY - yPos); break; case 3: case 5: for (int i = 0; i < penWidth; i++) { if (drawMode == 3) { g.drawRect(xPos, yPos, newX - xPos, newY - yPos); og.drawRect(xPos, yPos, newX - xPos, newY - yPos); } else { g.drawOval(xPos, yPos, newX - xPos, newY - yPos); og.drawOval(xPos, yPos, newX - xPos, newY - yPos); } xPos++; yPos++; newX--; newY--; } break; } } // Unused dummy methods for MouseMotionListener and MouseListener public void mouseClicked(MouseEvent me) { } public void mouseEntered(MouseEvent me) { } public void mouseExited(MouseEvent me) { } public void mouseMoved(MouseEvent me) { } }