/*
    File: DoubleBuffering.java

    Drawing in applets is almost always done with double-buffering.
    This means that drawing is first done to an offscreen image, and when all
    is done, the offscreen image is drawn on the screen.
    This reduces the nasty flickering applets otherwise have.
*/

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class DoubleBuffering extends Applet {

    private Graphics bufferGraphics;  // We'll draw on this instead of 'Graphics'
    private Image offscreen;  // This image will contain everything drawn on bufferGraphics.
    private Dimension dim;    // Save the dimensions of the applet.
    private Point cursor;     // Coordinates of the mouse/cursor.
    private Image image;
    private static final int DD = 33;

    public void init() {
        setBackground(Color.GRAY);
        dim = getSize();      // Get the applet's width and height.
        cursor = new Point(dim.width / 2, dim.height / 2);
        // We'll redraw the applet each time the mouse has moved.
        addMouseMotionListener(new MouseMotionHandler());
        // Create an offscreen image to draw on. Make it the size of the applet.
        // A larger size could slow it down unnecessary.
        offscreen = createImage(dim.width, dim.height);
        // Now everything that is drawn into bufferGraphics
        // will be written on the offscreen image.
        bufferGraphics = offscreen.getGraphics();
        image = getImage(getCodeBase(), "happyFace.gif");
    }

    public void paint(Graphics g) {
        // Wipe off everything that has been drawn before.
        // Otherwise previous drawings also would be displayed.
        bufferGraphics.clearRect(0, 0, dim.width, dim.width);

        // Draw the legend and the bounding frame
        bufferGraphics.setColor(Color.CYAN);
        bufferGraphics.drawString("Double-Buffered Drawing", 5, 15);
        bufferGraphics.drawLine(0, 0, dim.width-1, 0);
        bufferGraphics.drawLine(dim.width-1, 0, dim.width-1, dim.height-1);
        bufferGraphics.drawLine(dim.width-1, dim.height-1, 0, dim.height-1);
        bufferGraphics.drawLine(0, dim.height-1, 0, 0);

        // Draw at the current mouse position in the offscreen buffer.
        bufferGraphics.fillRect(cursor.x-DD, cursor.y-DD, DD, DD);
        bufferGraphics.setColor(Color.WHITE);
        bufferGraphics.drawRect(cursor.x-DD, cursor.y-DD, DD, DD);
        bufferGraphics.drawImage(image, cursor.x-DD, cursor.y-DD, this);

        // Draw the offscreen image to the screen like a normal image.
        // Since offscreen is the screen width, we start at (0, 0).
        g.drawImage(offscreen, 0, 0, this);

        showStatus("Move the mouse within the applet");
    }

    // An update method always is required for good double-buffering.
    // This will cause the applet not to first wipe off the
    // previous drawings but to repaint immediately.
    // Wiping off is one of the causes of flickering.
    // Update is called automatically when repaint() is called.

    public void update(Graphics g) {
        paint(g);
    }

    private class MouseMotionHandler implements MouseMotionListener {

        public void mouseMoved(MouseEvent me) {
            handleMouseMotion(me);
        }
    
        public void mouseDragged(MouseEvent me) {
            handleMouseMotion(me);
        }

        // Save the current cursor position to paint a shape there
        // later, and request a repaint().
        private void handleMouseMotion(MouseEvent me) {
            cursor = me.getPoint();
            repaint();
        }

    } // end class MouseMotionHandler

} // end class DoubleBuffering
