/** Extended 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 Doodle1 extends Applet {

  DrawingPad1 dPad;

  Button
         clearButton,
         biggerButton, smallerButton,
         undoButton;

  Checkbox
	 writeHButton, writeVButton,
         redButton, yellowButton, greenButton, blueButton;

  CheckboxGroup
	 writeHVGroup = new CheckboxGroup (),
         colorsGroup = new CheckboxGroup ();


/** Make everything,
 * a drawing surface and some controls. */

  public void init () {

/* A big central drawing area and some controls on the edges */

     setLayout (new BorderLayout ());

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

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

/* EXPLAIN WHAT A PANEL IS AND WHY USED */

     Panel np = new Panel ();
     np.setLayout (new GridLayout (0, 1));

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

/* Note set/getCurrent deprecated now set/getSelectedCheckbox */

     add ("West", np);

/* EXPLAIN WHY ANOTHER LAYOUT */

     Panel sp = new Panel ();
     sp.setLayout (new GridLayout (0, 1));

     sp.add (biggerButton = new Button ("bigger"));
     sp.add (smallerButton = new Button ("smaller"));

     sp.add (writeHButton = new Checkbox ("Write Horiz"));
     writeHButton.setCheckboxGroup (writeHVGroup);

     sp.add (writeVButton = new Checkbox ("Write Vert"));
     writeVButton.setCheckboxGroup (writeHVGroup);

     writeHVGroup.setCurrent (writeHButton);

     sp.add (yellowButton = new Checkbox ("yellow"));
     yellowButton.setCheckboxGroup (colorsGroup);

     sp.add (redButton = new Checkbox ("red"));
     redButton.setCheckboxGroup (colorsGroup);

     sp.add (greenButton = new Checkbox ("green"));
     greenButton.setCheckboxGroup (colorsGroup);

     sp.add (blueButton = new Checkbox ("blue"));
     blueButton.setCheckboxGroup (colorsGroup);

     colorsGroup.setCurrent (blueButton);

     add ("East", sp);
  }

/** Handle the button and say we did */

  public boolean action (Event e, Object o) {

/* Which button? */

     if (e.target == clearButton) dPad.clear ();
     if (e.target == biggerButton) dPad.bigger ();
     if (e.target == smallerButton) dPad.smaller ();

/* When one turns on another turns off -- handle just the on */

     if ((e.target == redButton)
      && redButton.getState ()) dPad.setPaint (Color.red);
     if ((e.target == yellowButton)
      && yellowButton.getState ()) dPad.setPaint (Color.yellow);
     if ((e.target == greenButton)
      && greenButton.getState ()) dPad.setPaint (Color.green);
     if ((e.target == blueButton)
      && blueButton.getState ()) dPad.setPaint (Color.blue);

      if ((e.target == writeHButton)
       && writeHButton.getState ()) dPad.setHV (0);

      if ((e.target == writeVButton)
       && writeVButton.getState ()) dPad.setHV (1);

/* dPad must requestFocus to get key strokes,
 * otherwise focus shifts to last thing clicked */

     dPad.requestFocus ();

     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) {

      Doodle1 cd = new Doodle1 ();

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

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

      ff.show ();
  }

}

class DrawingPad1 extends Canvas {

  Image di;
  Graphics dg;

  int xpos, ypos, xold, yold;

  int hv = 0;

  public void setPaint (Color fg) { dg.setColor (fg); }

  public void setHV (int m) { hv = m; }

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

     xold = x; yold = y;

     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 */

     repaint ();
     return true;
  }

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

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

  public void paint (Graphics g) {
     if (di == null) {
         di = createImage (size ().width, size ().height);
         dg = di.getGraphics ();
     }

/* Everything from the accumulated offscreen image */

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

/* Border */

     g.setColor (Color.black);
     g.drawRect (0, 0, size ().width-1, size ().height-1);
  }

  public void clear () {
     if (null != dg) {
         dg.clearRect (0, 0, size ().width, size ().height);
         dg.setColor (Color.black);
         dg.drawRect (0, 0, size ().width-1, size ().height-1);
     }
     repaint ();
  }

/* There is no keyClick just Down and Up.
 * "Keypress:C:NN"
 * C is String [1] for the key character if defined else "?".
 * NN is String [2 or more] for the numeric key code,
 * high numbers > 1000 are control keys. */

  public boolean keyDown (Event evt, int key) {
     if (dg == null) return false;

     if (key > 1000) return false;

 // System.out.println ("Keypress:"+String.valueOf ((char)key)+":"+String.valueOf (key));

     String ks = String.valueOf ((char)key);

     FontMetrics fm = dg.getFontMetrics ();

     dg.drawString (ks, xold, yold);

/* Advance either across or down */

     if (0 == hv)
         xold += fm.stringWidth (ks);
     else
         yold += fm.getHeight ();

     repaint ();
     return true;
  }

/** Must requestFocus to get key strokes */

  public synchronized boolean mouseEnter (Event me, int x, int y) {
     requestFocus ();
     return true;
  }

/** This **always** gives a newFont with getSize as requested,
 *  but they may be displayed as the same size anyway.
 *  and NOT change size on our Unix box,
 *  although fine on a Windows/NT box. */

  public void bigger () { changeFont (2); }

  public void smaller () { changeFont (-2); }

  void changeFont (int delta) {

     Component pcomp = getParent ();

     Font oldFont = getFont ();

     if ((null == oldFont)
      && (null != pcomp))
         oldFont = pcomp.getFont ();

     if (null == oldFont)
         return;

     Font newFont = new Font
          (oldFont.getName (),
           oldFont.getStyle (),
           oldFont.getSize () + delta);

/* Existing dg won't see it so tell them */

     setFont (newFont);
     dg.setFont (newFont);
   }

}
