import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/***********************************************************************
   DoubleBuffer is a rewrite of the Scrib Applet that provides an 
   off-screen buffer for repainting.
   
   Main idea:  We add a second Image called "offScreen" (besides the 
   viewable or "on-screen" Image that an Applet automatically gets) and 
   do our drawing on offScreen as well as the viewable Image.  Then, 
   when it comes time to paint(), we dump the contents of the off-screen 
   copy to the viewing screen.
************************************************************************/

public class DoubleBuffer extends JApplet {
  int lastX, lastY;

  Image offScreen;  // "off-screen" image buffer 

  public void init() {
    this.addMouseListener(new MyMouseAdapter());
    this.addMouseMotionListener(new MyMouseMotionAdapter());
  }

  // update() is called only by the window system as needed to update 
  // the contents of the viewable Image associated with this applet.  The 
  // default, Container.update(), clears the screen then calls paint(), 
  // so this should be faster (note we don't need to clear screen) */
  public void update(Graphics g) {
    paint(g);
  }

  // paint() actually does the repainting of the screen on demand from
  // the windowing system, i.e., whenever our image becomes newly visible. */
  public void paint(Graphics g) {
    if (offScreen == null) {
      /* We must allocate and initialize savedImage ourselves... 
         We do it here to avoid problems with Frames */
      offScreen = createImage(getSize().width, getSize().height);
      Graphics gSaved = offScreen.getGraphics();
      gSaved.setColor(getBackground());
      gSaved.fillRect(0, 0, getSize().width, getSize().height);
    }
    g.drawImage(offScreen, 0, 0, null);
  }


  class MyMouseAdapter extends MouseAdapter {
    // A method from the MouseListener interface.  Invoked when the
    // user presses a mouse button.
    public void mousePressed(MouseEvent e) {
      lastX = e.getX(); 
      lastY = e.getY();
    }
  }
  
  
  // We modify MyMouseMotionAdapter to draw on both images when a 
  // mouse drag event is encountered */
  class MyMouseMotionAdapter implements MouseMotionListener {
    // Invoked when the user drags the mouse with a button pressed.
    public void mouseDragged(MouseEvent e) {
      int x = e.getX(), y = e.getY();

      Graphics gSaved = offScreen.getGraphics();
      gSaved.drawLine(lastX, lastY, x, y);

      // there are two options here.  We can either draw the same 
      // thing on the on-screen image, or we can call repaint()
      Graphics g = getGraphics();
      g.drawLine(lastX, lastY, x, y);
      // repaint();  // queue a request for update()

      lastX = x; lastY = y;
    }
    
    // The other method of the MouseMotionListener interface.
    public void mouseMoved(MouseEvent e) {;}
  }
}