import java.applet.*;import java.awt.*;import java.util.*;    public class DrawLetter extends Applet implements Runnable/*****************************************************************************    DrawLetter -- Manual Drawing Surface to Practice Penmanship    History:      12/26/96  NDE  Fixed the clear button so that the drawing would start                     over after it was pressed.      12/12/96  NDE  Fixed null pointer problem when applet that was not                     drawing, was closed. *****************************************************************************/      {      final String PLAYBACK_PARM         = "playback";      final int PLAYBACK_DELAY_FACTOR    = 2;      final int PAUSE_BETWEEN_PICTURES   = 3500;      boolean bDrawing;                  /* The user is drawing on the screen*/      static Image imgDrawingDot = null; /* Image for user drawing.          */      StringBuffer sbDrawing;            /* String of drawing coordinates.   */      long msLatestCurrTime;             /* The latest cur time in millisecs.*/      boolean bPlayingback;              /* Playback is occuring.            */      static Image imgPlaybackDot = null;/* Image for playback drawing.      */      String sPlayback;                  /* String with playback coordinates.*/      Thread thPlayback;                 /* The playback thread.             */      boolean bRunning;                  /* Tracks thread run state (replace)*/      int iPlaybackNumber = 0;           /* Num of the current playback msg. */      int iNextPrompt = 0;               /* The next prompt to draw.         */      int iNumPrompts = 0;               /* Number of prompt text items.     */      int[] aiPromptQueue = new int[10]; /* Paint msg# for each prompt msg.  */      String[] asPromptText = new String[10];      int xMouse, yMouse;                /* Current position of the mouse.   */      int xPlayback, yPlayback;          /* Curr position of the playback img*/      int xScreen, yScreen;              /* Curr width and height of screen. */      int xHalfImage, yHalfImage;        /* Image size / 2.                  */      Button btnSave;                    /* Save drawing coordinates button. */      Button btnRedraw;                  /* Pause drawing button.            */      Button btnClear;                   /* Clear screen button.             */      boolean bInitScreen;               /* The screen needs to be initializd*//*****************************************************************************/      public void init ()        {         int i;        String s;        StringTokenizer st;        bInitScreen = true;        bDrawing = false;        xScreen = 0;        yScreen = 0;        xPlayback = 0;        yPlayback = 0;        xHalfImage = 5;        yHalfImage = 5;        sbDrawing = new StringBuffer ();        sPlayback = getParameter (PLAYBACK_PARM);        if (sPlayback != null)          {          bPlayingback = true;          if ((s = getParameter ("prompts")) != null)            {            iNumPrompts = new Integer(s).intValue ();            for (i = 0; i < iNumPrompts; i++)              {              s = getParameter ("prompt" + i);              if (s != null)                {                st = new StringTokenizer (s);                aiPromptQueue[i] = new Integer(st.nextToken()).intValue ();                s = st.nextToken ("~");                asPromptText[i] = s.trim ();                }              }            }          }        else          {          bPlayingback = false;          }        setBackground (Color.white);        btnSave = new Button ("Save");        add (btnSave);        if (bPlayingback)          {          btnRedraw = new Button ("  Redraw  ");          add (btnRedraw);          }        btnClear = new Button ("Clear");        add (btnClear);        repaint ();        }      public void run ()        {        long msWait;        StringTokenizer st;        initScreen ();        getImages (this);	bRunning = true;        st = new StringTokenizer (sPlayback);        while (bRunning)          {          try            {            xPlayback = (new Integer (st.nextToken ())).intValue ();            yPlayback = (new Integer (st.nextToken ())).intValue ();            msWait = (new Long (st.nextToken ())).longValue () * PLAYBACK_DELAY_FACTOR;            repaint (1, 1, xScreen - 1, yScreen - 1);            Thread.sleep (msWait);            }          catch (Exception e1)            {            break;            }          }        bRunning = false;        btnRedraw.enable ();        }      public void stop ()        {        if (bRunning)          {          bRunning = false;          thPlayback.stop ();          btnRedraw.enable ();          }        }      public boolean action(Event evt, Object obj)        {        if (evt.target == btnClear)          {          initScreen ();          repaint ();          }        else if (evt.target == btnRedraw)          {          if (bRunning)            {            System.out.println ("unexpected running press of pause");            }          else             {            if (bPlayingback)               {              thPlayback = new Thread (this);              thPlayback.start ();              btnRedraw.disable ();              }            }          }        else if (evt.target == btnSave)          {          System.out.println             (            "<param "            + "name=\""  + PLAYBACK_PARM         + "\" "            + "value=\"" + sbDrawing.toString () + "\""            + ">"            );          }        return (true);        }      public void update (Graphics g)         {        paint (g);        }      public void paint (Graphics g)         {        Rectangle r;        r = g.getClipRect ();        if ((bInitScreen)        || (r.width == xScreen)        || (r.height == yScreen))          {          if (bPlayingback)             {            if (bRunning)              {              bRunning = false;              thPlayback.stop ();              }            thPlayback = new Thread (this);            thPlayback.start ();            btnRedraw.disable ();            }          else            {            initScreen ();            }          }        if (bRunning && bPlayingback)          {          g.drawImage             (            imgPlaybackDot,             xPlayback - xHalfImage,             yPlayback - yHalfImage,             this            );          if ((iNextPrompt < iNumPrompts)          && (iPlaybackNumber++ == aiPromptQueue[iNextPrompt]))            {            g.setColor (Color.lightGray);            g.fillRect (0, (yScreen * 4) / 5, xScreen, yScreen / 5);            g.setColor (Color.black);            g.drawString (asPromptText[iNextPrompt], 10, yScreen - 15);            iNextPrompt++;            }          }        if (bDrawing)          {          g.drawImage             (            imgDrawingDot,             xMouse - xHalfImage,              yMouse - yHalfImage,             this            );          }        }      synchronized void initScreen ()        {        int i;        int iLineHeight;        Graphics g;        xScreen = size().width;        yScreen = size().height;        i = yScreen / 70;        iLineHeight = i > 1 ? i : 1;        g = getGraphics ();        g.clearRect (0, 0, xScreen, yScreen);        g.setColor (Color.lightGray);        g.fillRect (0, 0, xScreen, yScreen / 5);        g.fillRect ((xScreen * 0) / 7, (yScreen * 2) / 5,          xScreen / 7, iLineHeight);        g.fillRect ((xScreen * 2) / 7, (yScreen * 2) / 5,          xScreen / 7, iLineHeight);        g.fillRect ((xScreen * 4) / 7, (yScreen * 2) / 5,          xScreen / 7, iLineHeight);        g.fillRect ((xScreen * 6) / 7, (yScreen * 2) / 5,          xScreen / 7, iLineHeight);        g.fillRect (0, (yScreen * 3) / 5, xScreen, iLineHeight * 2);        g.fillRect (0, (yScreen * 4) / 5, xScreen, yScreen / 5);        g.setColor (Color.black);        if (!bPlayingback)          {          g.drawString ("Practice . . .", 10, yScreen - 15);          }        bInitScreen = false;        bDrawing = false;        iPlaybackNumber = 0;        iNextPrompt = 0;        sbDrawing = new StringBuffer ();        }      public boolean mouseDown (Event evt, int x, int y)         {        msLatestCurrTime = ((Date) new Date()).getTime ();        xMouse = x;        yMouse = y;        bDrawing = true;        repaint (x - (xHalfImage * 3), y - (yHalfImage * 3),          xHalfImage * 6, yHalfImage * 6);         return (true);        }      public boolean mouseDrag (Event evt, int x, int y)         {        long msCurrTime;        msCurrTime = ((Date) new Date()).getTime ();        sbDrawing.append (x + " " + y + " "          + (msCurrTime - msLatestCurrTime) + " ");        msLatestCurrTime = msCurrTime;        xMouse = x;         yMouse = y;        repaint (x - (xHalfImage * 3), y - (yHalfImage * 3),          xHalfImage * 6, yHalfImage * 6);         return (true);        }      static synchronized void getImages (Applet applet)        {        MediaTracker mt;        mt = new MediaTracker (applet);        if (imgPlaybackDot == null)          {          imgPlaybackDot = applet.getImage (applet.getDocumentBase (),            "dotblack.gif");          mt.addImage (imgPlaybackDot, 1);          try            {            mt.waitForID (1);            }          catch (InterruptedException e)            {            }          }        if (imgDrawingDot == null)          {          imgDrawingDot = applet.getImage (applet.getDocumentBase (),            "dotblue.gif");          mt.addImage (imgDrawingDot, 2);          try            {            mt.waitForID (2);            }          catch (InterruptedException e)            {            }          }        }      }/*============================(  End of Source  )============================*/
