    /*

     * JavASketch.java

     *

     * Version 2.0

     *

     * Written by:  Mark Masse

     * Date:  7-28-96  (original version: 12-23-95)

     *

     * This software is in the public domain, furnished "as is", without technical

     * support, and with no warranty, express or implied, as to its usefulness for

     * any purpose.

     */

    import java.applet.Applet;

    import java.awt.*;

    /**

     * An Applet that implements a JavASketch drawing "toy".

     * @author     Mark Masse

     * @version    2.0

     */

    public class JavASketch extends Applet {

      //DATA MEMBERS

      /**

       * The current x coordinate of the sketch-point.

       */

      protected int x;

      /**

       * The current y coordinate of the sketch-point.

       */

      protected int y;

      /**

       * Is true when drawing up and false otherwise.

       */

      protected boolean up;

      /**

       * Is true when drawing down and false otherwise.

       */

      protected boolean down;

      /**

       * Is true when drawing left and false otherwise.

       */

      protected boolean left;

      /**

       * Is true when drawing right and false otherwise.

       */

      protected boolean right;

      /**

       * The image used to create the graphics.

       */

      protected Image img;

      /**

       * The dimensions of the JavASketch.

       */

      protected Dimension dim;

      /**

       * The graphic content of the JavASketch.

       */

      protected Graphics gra;

      /**

       * The width of the JavASketch.

       */

      protected int w;

      /**

       * The height of the JavASketch.

       */

      protected int h;

      /**

       * The previous x-coordinate.

       */

      protected int lastx;

      /**

       * The previous y-coordinate.

       */

      protected int lasty;

      /**

       * Determines whether the first point has been added to the JavASketch.

       */

      protected boolean gotFirstPoint;

      /**

       * Determines whether the JavASketch needs to be updated.

       */

      protected boolean updateSketch = true;

      /**

       * Determines whether the Jav A Sketch was erased .

       */

      protected boolean shaken;

      /**

       * The initial angle of the left knob's ridges.

       */

      protected float leftKnobAngle;

      /**

       * The initial angle of the right knob's ridges.

       */

      protected float rightKnobAngle;

      //METHODS

      /**

       * Initialization of the JavASketch Applet

       */

      public void init() {

        // Set the bg color to white

        setBackground(Color.white);

        // Set the starting point

        x = 200;

        y = 100;

        // Add the starting point to the JavASketch

        addPoint(x,y);

        showStatus("Jav A Sketch written by Mark Masse");

      }

      /**

       * Info

       * @return Info about the Applet's author

       */

      public String getAppletInfo() {

        return "JavASketch by Mark Masse";

      }

      /**

       * The event-handler for the JavASketch Applet.

       * @param evt         The Event

       */

      public boolean handleEvent(Event evt) {

        switch(evt.id) {

          case Event.KEY_PRESS:

          case Event.KEY_ACTION:

    	// Bind Space to erase the Jav A Sketch

    	if(evt.key == ' ') {

              showStatus("Shaking Jav A Sketch");

              shake();

              addPoint(x, y);

              repaint();

            }

    	//

    	// Bind the key press events to "turn on" direction

    	//

            else if(evt.key == 'l' || evt.key == 'L' || evt.key == Event.UP) {

    	  draw("UP", true);

            }

            else if(evt.key == 'k' || evt.key == 'K' || evt.key == Event.DOWN) {

    	  draw("DOWN", true);

            }

            else if(evt.key == 'a' || evt.key == 'A' || evt.key == Event.LEFT) {

    	  draw("LEFT", true);

            }

            else if(evt.key == 's' || evt.key == 'S' || evt.key == Event.RIGHT) {

    	  draw("RIGHT", true);

            }

    	break;

          case Event.KEY_RELEASE:

          case Event.KEY_ACTION_RELEASE:

    	//

    	// Bind the key release events to "turn off" direction

    	//

            if(evt.key == 'a' || evt.key == 'A' || evt.key == Event.LEFT) {

    	  draw("LEFT", false);

    	}

            else if(evt.key == 's' || evt.key == 'S' || evt.key == Event.RIGHT) {

    	  draw("RIGHT", false);

    	}

            else if(evt.key == 'k' || evt.key == 'K' || evt.key == Event.DOWN) {

    	  draw("DOWN", false);

    	}

            else if(evt.key == 'l' || evt.key == 'L' || evt.key == Event.UP) {

    	  draw("UP", false);

    	}

    	break;

          case Event.MOUSE_DOWN:

            showStatus("a = left, s = right, k = down, l = up," +

    		   " and space = erase");

            break;

        }

        return true;

      }

      /**

       * Paints the JavASketch with the current graphic content

       * @param g            The graphics content

       */

      public void paint(Graphics g) {

      	update(g);

      }

      /**

       * Updates the graphic content of the JavASketch

       * @param ig           The graphics content

       */

      public void update(Graphics igra) {

        Dimension d = size();

        if ((img == null) || (d.width != dim.width) || (d.height != dim.height)) {

          w   = d.width;

          h   = d.height;

          img  = createImage(w, h);

          dim = d;

          gra  = img.getGraphics();

          updateSketch = true;

        }

        // Check to see if the erasing "shake" should be performed

        if(shaken) {

          int i, j;

          int distance = 50;

          // Shake up and down

          for(i=0; i < 3; i++) {

    	distance -= 10;

    	for(j=0; j >= -100; j-=distance) {

    	  igra.drawImage(img, 0, j, null);

    	}

    	for(j=-100; j <= 100; j+=distance) {

    	  igra.drawImage(img, 0, j, null);

    	}

    	for(j=100; j >= 0; j-=distance) {

    	  igra.drawImage(img, 0, j, null);

    	}

          }

          shaken = false;

        }

        if(updateSketch) {

          // Redraw the JavASketch

          // NOTE:  This will erase the current sketch

          drawSketch();

          updateSketch = false;

        }

        igra.drawImage(img, 0, 0, null);

      }

      /**

       * Draws all of the graphics for the JavASketch.  Including the

       * red border, and the "Jav A sketch" title

       */

      public void drawSketch() {

        // Draw the red border

        gra.setColor(Color.red);

        gra.fillRoundRect(0, 0, w, h, 80, 80);

        // Draw main rectangular drawing surface

        gra.setColor(Color.gray);

        gra.fillRoundRect(40, 40, w-80, h-130, 20, 20);

        gra.setColor(Color.lightGray);

        gra.fillRoundRect(43, 43, w-86, h-136, 20, 20);

        // Create the color fdd017

        Color Gold = new Color(253, 208, 23);

        gra.setColor(Gold);

        // Create Polygon for left arrow

        Polygon leftArrow = new Polygon();

        // Create Polygon for right arrow

        Polygon rightArrow = new Polygon();

        // Create Polygon for up arrow

        Polygon upArrow = new Polygon();

        // Create Polygon for down arrow

        Polygon downArrow = new Polygon();

        // Add points to leftArrow Polygon

        leftArrow.addPoint(10,h-95);

        leftArrow.addPoint(20,h-105);

        leftArrow.addPoint(20,h-85);

        // Add points to rightArrow Polygon

        rightArrow.addPoint(34,h-95);

        rightArrow.addPoint(24,h-105);

        rightArrow.addPoint(24,h-85);

        // Add points to downArrow Polygon

        downArrow.addPoint(w-20,h-85);

        downArrow.addPoint(w-10,h-95);

        downArrow.addPoint(w-30,h-95);

        // Add points to upArrow Polygon

        upArrow.addPoint(w-20,h-109);

        upArrow.addPoint(w-10,h-99);

        upArrow.addPoint(w-30,h-99);

        // Fill the Arrow Polygons

        gra.fillPolygon(leftArrow);

        gra.fillPolygon(rightArrow);

        gra.fillPolygon(downArrow);

        gra.fillPolygon(upArrow);

        // Draw left knob

        drawKnob(0, h - 80, 80, leftKnobAngle);

        // Draw right knob

        drawKnob(w - 80, h - 80, 80, rightKnobAngle);

        // Print "Jav A sketch" at the top

        Font JS = new Font("JS", Font.ITALIC, 25);

        gra.setFont(JS);

        FontMetrics fm = gra.getFontMetrics();

        int sWidth = fm.stringWidth("Jav A Sketch");

        gra.drawString("Jav A Sketch",(w - sWidth)/2, 25);

        // If we didn't just erase then show author info.

        if(!shaken) {

          showStatus("Jav A Sketch written by Mark Masse");

        }

      }

      /**

       * Clears the JavASketch screen.

       */

      public void shake() {

        shaken = true;

        updateSketch = true;

        up = false;

        down = false;

        left = false;

        right = false;

        repaint();

      }

      public void drawKnob(int x, int y, int diameter, float startAngle) {

        Color oldColor = gra.getColor();

        // Draw the knob's border

        gra.setColor(Color.lightGray);

        gra.fillOval(x, y, diameter, diameter);

        float radius = (float) diameter/2;

        int centerX = x + (int) radius;

        int centerY = y + (int) radius;

        // Draw the knotches that will "move"

        gra.setColor(Color.gray);

        for(float angle = startAngle;

    	angle <= (360.0f + startAngle); angle += 10.0f) {

          int borderX = centerX + (int) (radius *

    			   ((float) Math.cos((double) angle)));

          int borderY = centerY + (int) (radius *

    			   ((float) Math.sin((double) angle)));

          gra.drawLine(centerX, centerY, borderX, borderY);

        }

        gra.setColor(Color.white);

        gra.fillOval(x + 4, y + 4, diameter - 8, diameter - 8);

        // Draw a dot in the center

        gra.setColor(Color.lightGray);

        gra.fillOval(centerX - 1, centerY - 1, 2, 2);

        gra.setColor(oldColor);

      }

      public void turnLeftKnob(String direction) {

        if(direction.equalsIgnoreCase("RIGHT")) {

          leftKnobAngle -= 2.5f;

        }

        else {

          leftKnobAngle += 2.5f;

        }

        if(leftKnobAngle >= 360.0f) {

          leftKnobAngle = 0.0f;

        }

        // Draw left knob

        drawKnob(0, h - 80, 80, leftKnobAngle);

      }

      public void turnRightKnob(String direction) {

        if(direction.equalsIgnoreCase("UP")) {

          rightKnobAngle -= 2.5f;

        }

        else {

    	rightKnobAngle += 2.5f;

        }

        if(rightKnobAngle >= 360.0f) {

          rightKnobAngle = 0.0f;

        }

        // Draw right knob

        drawKnob(w - 80, h - 80, 80, rightKnobAngle);

      }

      /**

       * First checks to make sure the point specified by the parameters x and y

       * is in the sketching area, and if so it adds the point.  If the point is

       * outside the sketching area, the Applet's x and y values are reset to be

       * inside the area.

       * @param x              The x coordinate of the point to be added

       * @param y              The y coordinate of the point to be added

       */

      public void checkAndAdd(int X, int Y) {

        int border = 45;

        int bottomBorder = 95;

        if((X > border && X < w - border) &&

           (Y > border && Y < h - bottomBorder)) {

          addPoint(X, Y);

          repaint();

        }

        else if(X < border)

        this.x = border + 2;

        else if(X > w - border)

        this.x = w - border - 2;

        else if(Y < border)

        this.y = border + 2;

        else if(Y > h - bottomBorder)

        this.y = h - bottomBorder - 2;

      }

      /**

       * Adds a "sketch"-point to the JavASketch.

       * @param x              The x coordinate of the point to be added.

       * @param y              The y coordinate of the point to be added.

       */

      public void addPoint(int x, int y) {

        if(gotFirstPoint) {

          // "Connect the dots"

          gra.setColor(Color.black);

          gra.drawLine(x , y, lastx, lasty);

          // Draw the cursor as a light gray pixel

          gra.setColor(Color.lightGray);

          gra.drawLine(x, y, x, y);

        }

        // Set the "last" variables for the next call to this function

        lastx = x;

        lasty = y;

        gotFirstPoint = true;  // Set because this function has been called

      }

      public void draw(String direction, boolean state) {

        if(state) {

          if(direction.equalsIgnoreCase("UP") ||

    	 direction.equalsIgnoreCase("DOWN")) {

    	if(direction.equalsIgnoreCase("UP")) {

    	  up = true;

    	  down = false;

    	  y = y - 4;

    	  turnRightKnob("UP");

    	}

    	else {

    	  down = true;

    	  up = false;

    	  y = y + 4;

    	  turnRightKnob("DOWN");

    	}

    	if(left) {

    	  x = x - 4;

    	  turnLeftKnob("LEFT");

    	}

    	else if(right) {

    	  x = x + 4;

    	  turnLeftKnob("RIGHT");

    	}

          }

          else if(direction.equalsIgnoreCase("LEFT") ||

    	     direction.equalsIgnoreCase("RIGHT")) {

    	if(direction.equalsIgnoreCase("LEFT")) {

    	  left = true;

    	  right = false;

    	  x = x - 4;

    	  turnLeftKnob("LEFT");

    	}

    	else {

    	  right = true;

    	  left = false;

    	  x = x + 4;

    	  turnLeftKnob("RIGHT");

    	}

    	if(up) {

    	  y = y - 4;

    	  turnRightKnob("UP");

    	}

    	else if(down) {

    	  y = y + 4;

    	  turnRightKnob("DOWN");

    	}

          }

          checkAndAdd(x, y);

        }

        else {

          if(direction.equalsIgnoreCase("UP")) {

    	up = false;

          }

          else if(direction.equalsIgnoreCase("DOWN")) {

    	down = false;

          }

          else if(direction.equalsIgnoreCase("LEFT")) {

    	left = false;

          }

          else if(direction.equalsIgnoreCase("RIGHT")) {

    	right = false;

          }

        }

      }

    }