/** From the DoodlePad example in Exploring Java,
 * by Patrick Niemeyer and Joshua Peck,
 * First edition Copyright 1996 O'Reilly Publishing. */

import java.awt.*;
import java.applet.*;

public class Doodle extends Applet {

  DrawingPad dPad;

  Button clearButton;

/** Make everything,
 * a drawing surface and control. */

  public void init () {

/* EXPLAIN LAYOUT AND WHY NEEDED */

/* A big central drawing area and control area at edge */

     setLayout (new BorderLayout ());

     add ("Center", dPad = new DrawingPad ());

      dPad.setBackground (Color.white);
      dPad.setForeground (Color.blue);

     Panel np = new Panel ();

     np.add (clearButton = new Button ("Clear"));

     add ("North", np);
  }

/** Handle the drawn button click action */

  public boolean action (Event e, Object o) {
     if (e.target == clearButton) dPad.clear ();

/* and say we took care of event so it goes no further */

     return true;
  }

/** To run as an application,
 * construct it and show it in a frame.
 * This must be a static (class not instance) method,
 * because the instance won't exist until we construct it here.
 * When run as an applet,
 * the browser provides the frame,
 * and calls the constructor and init methods. */

  public static void main (String []argv) {

      Doodle cd = new Doodle ();

      Frame ff = new Frame ("Doodle");
      ff.setBounds (100, 100, 600, 300);

      ff.add (cd);
      cd.init ();

      ff.show ();
  }

}

class DrawingPad extends Canvas {

/* EXPLAIN DOUBLE BUFFERING AND OFFSCREEN IMAGE */

  Image di;
  Graphics dg;

  int xpos, ypos, xold, yold;

/** Save mouse position when pressed */

  public boolean mouseDown (Event e, int x, int y) {

     xold = x; yold = y;

/* and say we took care of event so it goes no further */

     return true;
  }

  public boolean mouseDrag (Event e, int x, int y) {

/* add another line segment to the offscreen image. */

     xpos = x; ypos = y;
     if (dg != null)
         dg.drawLine (xold, yold, xpos, ypos);
     xold=xpos; yold=ypos;

/* we need a repaint so latest offscreen image will show */

     repaint ();

/* and say we took care of event so it goes no further */

     return true;
  }

/** Prevent usual pre-clear since we fill whole space anyway */

  public void update (Graphics g) { paint (g); }

  public void paint (Graphics g) {

/* If offscreen image hasn't been created yet do so now */

     if (di == null) {
         di = createImage (size ().width, size ().height);
         dg = di.getGraphics ();
     }

/* Everything from the accumulated offscreen image to screen */

     g.drawImage (di, 0, 0, null);
  }

  public void clear () {
     if (di != null)
         dg.clearRect (0, 0, size ().width, size ().height);
     repaint ();
  }

}
