home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Internet / Javadraw / DATA.Z / Addon.tmp < prev    next >
Text File  |  1996-07-11  |  62KB  |  2,142 lines

  1. /*
  2.  * Copyright (c) 1996 by Jan Andersson, Torpa Konsult AB.
  3.  *
  4.  * Permission to use, copy, and distribute this software for
  5.  * NON-COMMERCIAL purposes and without fee is hereby granted
  6.  * provided that this copyright notice appears in all copies.
  7.  */
  8. import java.applet.*;
  9. import java.awt.*;
  10. import java.util.*;
  11. import java.io.*;
  12. import java.net.*;
  13. import java.awt.*;
  14.  
  15.  
  16. /**
  17.  * FunScroll - A Funnier (?) scrolling text applet.
  18.  *
  19.  * @version 1.27 96/09/06
  20.  * @author  Jan Andersson (janne@torpa.se)
  21.  * 
  22.  */
  23. public class FunScroll extends Applet implements Runnable 
  24. {            
  25.    static final int MaxLines = 50; // max no. of line parameters
  26.    static final int ShadowIn = 0;  // frame types:
  27.    static final int ShadowOut = 1;
  28.    static final int ShadowEtchedIn = 2;
  29.    static final int ShadowEtchedOut = 3;
  30.    
  31.    Image bgImage = null;    // backgound image
  32.    Image tiledBgImage = null;    // tiled backgound image
  33.    MediaTracker mediaTracker;   // to track loading of backgound image
  34.    Thread thread = null;    // animation thread
  35.    ThreadGroup threadGroup = null; // animation thread group
  36.    boolean suspended = false;    // animation thread suspended
  37.    int threadDelay = 100;    // animation thread delay 
  38.    String lineData = null;    // line data file (url)
  39.    int updateInterval = 0;    // update interval (to read data file)
  40.    int animateCount = 0;    // reload data (from data file)
  41.    Font font = null;        // default font
  42.    int dx = 3;            // delta x
  43.    int dy = 2;            // delta y
  44.    String delim = null;        // text attribute delimiters
  45.    long threadStartTime;    // time thread started
  46.    Vector animatedTexts = null;    // animated texts
  47.    Vector urlStrings = null;    // associated url's
  48.    String urlTarget = null;    // target widow or frame
  49.    int noOfTexts = 0;        // number of texts
  50.    int currentTextIndex = 0;    // current text index
  51.    FunScrollAnimatedText currentText;    // current text instance
  52.    int frameWidth = 0;        // frame width
  53.    int frameType = ShadowIn;    // frame type
  54.    int frameMargin = 0;        // frame margin
  55.    Color frameDark1 = null;    // darker frame color
  56.    Color frameDark2 = null;    // (slightly) darker frame color
  57.    Color frameBright = null;    // brighter frame color
  58.    Image offImage;        // "off-screen" image
  59.    Graphics offGraphics;    // "off-screen" graphics
  60.    Dimension offSize;        // "off-screen" size
  61.    Dimension textSize;        // textArea size
  62.    protected boolean initiated = false;    // true when initiated
  63.    
  64.    static final boolean debug = false;// debug flag
  65.    static final String sourceLocation =
  66.           "http://www.algonet.se/FunScroll/FunScroll.html";
  67.    static final String versionInfo =
  68.           "FunScroll 2.3";
  69.    
  70.    /**
  71.     * Init applet
  72.     */
  73.    public void init()
  74.    {
  75.       // we need a few parameters to draw the initial message...
  76.  
  77.       // get color parameters
  78.       Color fg = readColor(getParameter("fgColor"), Color.black);
  79.       Color bg = readColor(getParameter("bgColor"), Color.white);
  80.       threadDelay = 40;
  81.       resize (500, 300);
  82.       //ID Insert Mark 2
  83.       setForeground(fg);
  84.       setBackground(bg);
  85.  
  86.       // create the initial offscreen graphics context
  87.       offSize = size();
  88.       offImage = createImage(offSize.width, offSize.height);
  89.       offGraphics = offImage.getGraphics();
  90.  
  91.       // get current Thread group
  92.       threadGroup = Thread.currentThread().getThreadGroup();
  93.    }
  94.  
  95.    /**
  96.     * Init parameters and create animated text instances
  97.     */
  98.    public void initParameters()
  99.    {
  100.       Vector lineVector = new Vector();
  101.       urlStrings = new Vector();
  102.       
  103.       String par = getParameter("lineData");
  104.       if (par != null) {
  105.      lineData = par;
  106.      initLineParametersFromInputURL(lineData, lineVector, urlStrings);
  107.      par = getParameter("updateInterval");
  108.      if (par != null) 
  109.         updateInterval = Integer.valueOf(par).intValue();
  110.       }
  111.       else 
  112.      initLineParameters(lineVector, urlStrings);
  113.  
  114.       // init frame (border) params
  115.       par = getParameter("frameWidth");
  116.       if (par != null)
  117.      frameWidth = Integer.valueOf(par).intValue();
  118.       par = getParameter("frameMargin");
  119.       if (par != null)
  120.      frameMargin = Integer.valueOf(par).intValue();
  121.       par = getParameter("frameType");
  122.       if (par != null) {
  123.      if (par.equalsIgnoreCase("ShadowOut"))
  124.         frameType = ShadowOut;
  125.      else if (par.equalsIgnoreCase("ShadowEtchedIn"))
  126.         frameType = ShadowEtchedIn;
  127.      else if (par.equalsIgnoreCase("ShadowEtchedOut"))
  128.         frameType = ShadowEtchedOut;
  129.      else
  130.         frameType = ShadowIn;
  131.       }
  132.       
  133.       // get frame/window target
  134.       urlTarget = getParameter("target");
  135.  
  136.       bgImage = getImage(getCodeBase(), "");
  137.   //ID Insert Mark 4    
  138.   mediaTracker = new MediaTracker(this);
  139.      mediaTracker.addImage(bgImage, 0);
  140.  
  141.       // get font parameters
  142.       
  143.       String fontName = "TimesNewRoman";
  144.       String fontSize = "10";
  145.       String fontStyle = "BOLD";
  146.       //ID Insert Mark 3
  147.       
  148.       if (fontName == null)
  149.      fontName = "TimesRoman";
  150.  
  151.       int style = Font.BOLD;
  152.       if (fontStyle != null) {
  153.      if (fontStyle.equalsIgnoreCase("plain"))
  154.         style = Font.PLAIN;
  155.      else if (fontStyle.equalsIgnoreCase("bold"))
  156.         style = Font.BOLD;
  157.      else if (fontStyle.equalsIgnoreCase("italic"))
  158.         style = Font.ITALIC;
  159.       }
  160.  
  161.       if (fontSize == null)
  162.      fontSize = "24";
  163.       int size = Integer.valueOf(fontSize).intValue();
  164.  
  165.       // make sure fonts are created with the right size
  166.       // Note: size-parameter are plattform dependent and the
  167.       // only way to get the same size on all plattforms is to
  168.       // check the "real" size using FontMetrics.
  169.       // Note: we only loop until "real" size if less than 6
  170.       // or size differs more that 3 pixels...
  171.       FontMetrics fm;
  172.       int realSize = size;
  173.       dbg("init font...");
  174.       do {
  175.      dbg("trying: " + fontName + "," + realSize);
  176.      font = new Font(fontName, style, realSize--);
  177.      fm = getFontMetrics(font);
  178.       } while ((fm.getDescent() + fm.getAscent()) > size &&
  179.            realSize >= size-3 && size >= 6);
  180.       if (realSize < size-3 || size < 6) 
  181.      // assume weird font used... Use parsed size.
  182.      font = new Font(fontName, style, size);
  183.       
  184.       // get animation thread delay time
  185.       par = getParameter("delay");
  186.       if (par != null) 
  187.      threadDelay = Integer.valueOf(par).intValue();
  188.  
  189.       // get dx/dy movement
  190.       par = getParameter("dx");
  191.       if (par != null) 
  192.      dx = Integer.valueOf(par).intValue();
  193.       par = getParameter("dy");
  194.       if (par != null) 
  195.      dy = Integer.valueOf(par).intValue();
  196.  
  197.       // get delimiters string
  198.       delim = getParameter("delim");
  199.  
  200.       // create animated texts
  201.       createAnimatedTexts(lineVector,
  202.               font, getForeground(), getBackground(),
  203.               dx, dy, delim);
  204.       initiated = true;
  205.    }
  206.  
  207.    /**
  208.     * Gets a parameter of the applet.
  209.     *
  210.     * Use this function to overload java.applet.Applet.getParameter
  211.     * to handle ISO Latin 1 characters correctly in Netscape 2.0.
  212.     * Following a suggestion from Peter Sylvester,
  213.     * Peter.Sylvester@edelweb.fr.
  214.     *
  215.     * Note: this is a work-a-round for a bug in Netscape and should
  216.     *       be removed!
  217.     */
  218.    public String getParameter(String s) {
  219.       String tmp = super.getParameter(s);
  220.       if (tmp == null)
  221.      return null;
  222.       char ec[] = tmp.toCharArray();
  223.       for (int i=0; i < ec.length; i++) {
  224.      if (ec[i] >= 0xff00) 
  225.         ec[i] &= 0x00ff ;
  226.       }
  227.       return(new String(ec)) ;
  228.    }
  229.  
  230.    /**
  231.     * Init unparsed line parameters (Vector of Strings) and
  232.     * (possibly) associated url's.
  233.     */
  234.    protected void initLineParameters(Vector lineVector, Vector urlVector)
  235.    {
  236.    
  237.       // get unparsed line parameters
  238.       dbg("get line parameters...");
  239.       for (int i=0; i<MaxLines; i++) {
  240.      String lineParName = "line" + i;
  241.      String linePar=getParameter(lineParName);
  242.   String urlParName = "url" + i;
  243.      String urlPar = getParameter(urlParName);
  244.      if (linePar != null) {
  245.         dbg("  " + lineParName + ":" + linePar);
  246.         lineVector.addElement(linePar);
  247.         dbg("  " + urlParName + ":" + urlPar);
  248.         urlVector.addElement(urlPar);
  249.      }
  250.       }
  251.  
  252.       if (lineVector.size() <= 0)
  253.      // assume no line parameter provided; use default
  254.      initDefaultLineParameters(lineVector);
  255.    }
  256.  
  257.    /**
  258.     * Init unparsed line parameters (Vector of Strings) and
  259.     * (possibly) associated url's from input file.
  260.     */
  261.    protected void initLineParametersFromInputURL(
  262.       String urlString, Vector lineVector, Vector urlVector) {
  263.       // create URL
  264.       URL url = null;
  265.       DataInputStream is = null;
  266.       
  267.       // 1'st, try URL in context of document
  268.       try {
  269.      url = new URL(getDocumentBase(), urlString);
  270.      is = new DataInputStream(url.openStream());
  271.       } catch (Exception e) {
  272.      is = null;
  273.       }
  274.       
  275.       if (is == null) {
  276.      // then try URL directly
  277.      try {
  278.         url = new URL(urlString);
  279.         is = new DataInputStream(url.openStream());
  280.      } catch (Exception e) {
  281.         dbg("initLineParametersFromInputURL(): Can't read URL");
  282.         initURLErrorLineParameters(urlString, lineVector);
  283.         updateInterval = 0;
  284.         return;
  285.      }
  286.       }
  287.  
  288.       // read from input stream
  289.       try {
  290.      String line = null;
  291.      line = is.readLine();
  292.      while (line != null) {
  293.         // add to line vector
  294.         if (line.length() > 0)
  295.            lineVector.addElement(line);
  296.         line = is.readLine();
  297.         // add to url vector
  298.         if (line != null && line.length() > 4 &&
  299.         line.substring(0, 4).equalsIgnoreCase("URL:")) {
  300.            // assume url specified...
  301.            urlVector.addElement(line.substring(4));
  302.            line = is.readLine();
  303.         }
  304.         else {
  305.            urlVector.addElement(null);
  306.         }
  307.      }
  308.      is.close();
  309.       }
  310.       catch (IOException e) {
  311.      // ignore (?)
  312.       }
  313.  
  314.       if (lineVector.size() <= 0) {
  315.      // assume no line parameter provided; use error message
  316.      dbg("initLineParametersFromInputURL(): No lines!");
  317.      initURLErrorLineParameters(urlString, lineVector);
  318.      updateInterval = 0;
  319.       }
  320.    }
  321.    
  322.    /**
  323.     * Init default line parameters (Vector of Strings).
  324.     * Used when not line parameters specified.
  325.     */
  326.    protected void initDefaultLineParameters(Vector v) 
  327.       {
  328.       v.addElement ("<down><color=black>Insert here your text for scroll sequence 1:<down>");
  329.       v.addElement ("<down><color=black>Insert here your text for scroll sequence 2:<down>");
  330.       v.addElement ("<down><color=black>Insert here your text for scroll sequence 3:<down>");
  331.       v.addElement ("<down><color=black>Insert here your text for scroll sequence 4:<down>");
  332.       v.addElement ("<down><color=black>Insert here your text for scroll sequence 5:<down>");
  333.       v.addElement ("<down><color=black>Insert here your text for scroll sequence 6:<down>");
  334.       v.addElement ("<down><color=black>Insert here your text for scroll sequence 7:<down>");
  335.       v.addElement ("<down><color=black>Insert here your text for scroll sequence 8:<down>");
  336.       //ID Insert Mark 1
  337.       }
  338.  
  339.    /**
  340.     * Init error line parameters (Vector of Strings).
  341.     * Used at error, when trying to get input from URL.
  342.     */
  343.    protected void initURLErrorLineParameters(String url, Vector v) {
  344.       v.addElement("<nervous><30><color=#FF0000>Error!");
  345.       v.addElement("<100>Could not read url: " + url);
  346.    }
  347.  
  348.    /**
  349.     * Applet Info.
  350.     */
  351.    public String getAppletInfo() {
  352.       return versionInfo;
  353.    }   
  354.  
  355.    /**
  356.     * Parameter Info.
  357.     */
  358.    public String[][] getParameterInfo() {
  359.       // More should be added...
  360.       String[][] info = {
  361.      {"line<n>", "string", "Message line <n>" },
  362.      {"url<n>",  "string", "URL <n>" },
  363.      {"lineData","string", "Message line data file" },
  364.      {"updateInterval",  "int", "Update interval to read data file (0)" },
  365.      {"delim",   "string", "Delimiter string (<>)" },
  366.      {"frameWidth",  "int", "Frame border width (0)" },
  367.      {"frameMargin", "int", "Frame margin width (0)" },
  368.      {"frameType", "string", "Frame type (ShadowIn)" },
  369.      {"font",    "string", "Message font (TimesRoman)" },
  370.      {"style",   "string", "Message font style (bold)" },
  371.      {"size",    "int",    "Message font size (22)" },
  372.      {"delay",   "int",    "Animation delay time in millisec. (100)" },
  373.      {"dx",      "int",
  374.             "No of pixels to move horizontally for each animation (2)" },
  375.      {"dy",      "int",
  376.             "No of pixels to move vertically for each animation (1)" },
  377.      {"fgColor", "string", "Foreground Color" },
  378.      {"bgColor", "string", "Background Color" },
  379.       };
  380.       return info;
  381.    }
  382.    
  383.    /**
  384.     * Convert a Hexadecimal String with RGB-Values to Color
  385.     * Uses aDefault, if no or not enough RGB-Values
  386.     */
  387.    public Color readColor(String aColor, Color aDefault) {
  388.       if (aColor == null)
  389.      return aDefault;
  390.  
  391.       Integer rgbValue = null;
  392.       try {
  393.      if (aColor.startsWith("#")) 
  394.         rgbValue = Integer.valueOf(aColor.substring(1), 16);
  395.      else if (aColor.startsWith("0x")) 
  396.         rgbValue = Integer.valueOf(aColor.substring(2), 16);
  397.      else
  398.         // assume symbolic color name
  399.         rgbValue = Integer.valueOf(FunScrollColorSupport.lookup(aColor), 16);
  400.       } catch (NumberFormatException e) {
  401.      rgbValue = null;
  402.       }
  403.       
  404.       if (rgbValue == null)
  405.      return aDefault;
  406.       
  407.       return new Color(rgbValue.intValue());
  408.    }
  409.  
  410.    
  411.    
  412.    /**
  413.     * Create animated text vector. I.e vector with FunScrollAnimatedText
  414.     * instances.
  415.     */
  416.    public void createAnimatedTexts(Vector lines, Font font,
  417.                    Color fg, Color bg,
  418.                    int dx, int dy,
  419.                    String delim)
  420.    {
  421.       noOfTexts = 0;
  422.       animatedTexts = new Vector(lines.size());
  423.       dbg("Creating Animated Text...");
  424.       for (int i=0; i<lines.size(); i++) {
  425.      dbg("  " + (String) lines.elementAt(i));
  426.          animatedTexts.addElement(
  427.             new FunScrollAnimatedText(
  428.            this, (String) lines.elementAt(i), font,
  429.            fg, bg, dx, dy, delim));
  430.      noOfTexts++;
  431.       }
  432.       currentTextIndex = 0;
  433.       currentText = (FunScrollAnimatedText)
  434.      animatedTexts.elementAt(currentTextIndex);
  435.  
  436.       offImage = null;        // to be sure...
  437.    }
  438.    
  439.  
  440.    /**
  441.     * Animate the texts
  442.     */
  443.    public void animate(Graphics g, int offset, int width, int height) {
  444.       // update current text
  445.       if (currentText.update(g)) {
  446.      // done; get next text
  447.      currentTextIndex++;
  448.      if (currentTextIndex >= noOfTexts) {
  449.         // all text lines animated
  450.         if (lineData != null && updateInterval > 0)
  451.            animateCount++;
  452.         currentTextIndex = 0;
  453.      }
  454.      currentText = (FunScrollAnimatedText)
  455.         animatedTexts.elementAt(currentTextIndex);
  456.      currentText.reset(offset, width, height, g);
  457.       }
  458.    }
  459.    
  460.    /**
  461.     * Paint tiled background image.
  462.     * Based on code by Tony Kolman, 02/20/96.
  463.     *
  464.     * Note: there are performance problems here.
  465.     */
  466.    public void paintTiledImage(Graphics g, Image im,
  467.                    int offset, int width, int height) {
  468.       if (tiledBgImage == null) {
  469.      int imgw = im.getWidth(null);
  470.      int imgh = im.getHeight(null);
  471.      if (imgw > 0 && imgh > 0) {
  472.         // we have the background image; create tiled background image
  473.         tiledBgImage = createImage(width, height);
  474.         Graphics tiledBgGraphics = tiledBgImage.getGraphics();
  475.         tiledBgGraphics.setColor(getBackground());
  476.         tiledBgGraphics.fillRect(0, 0, width, height);
  477.         for (int x = 0; x < width; x += imgw) {
  478.            for (int y = 0; y < height; y += imgh) {
  479.           tiledBgGraphics.drawImage(im, x, y, null);
  480.            }
  481.         }
  482.      }
  483.       }
  484.       if (tiledBgImage != null) {
  485.      g.drawImage(tiledBgImage, offset, offset, null);
  486.       }
  487.    }
  488.  
  489.    /**
  490.     * Paint last animation
  491.     */
  492.    public void paint(Graphics g) {
  493.       if (offImage != null)
  494.      // paint the image onto the screen
  495.      g.drawImage(offImage, 0, 0, null);
  496.    }
  497.  
  498.    /**
  499.     * Paint "loading..." message
  500.     */
  501.    public void paintLoadMessage(Graphics g)
  502.    {
  503.       dbg("paintLoadMessage()");
  504.       offGraphics.setColor(getBackground());
  505.       offGraphics.fillRect(0, 0, offSize.width, offSize.height);
  506.       offGraphics.setColor(getForeground());
  507.       offGraphics.drawString("FunScroll: Loading applet...", 10, 10);
  508.       // Paint the image onto the screen
  509.       g.drawImage(offImage, 0, offSize.height/3 , null);
  510.    }
  511.  
  512.    /**
  513.     * Draw a frame at the specified position.
  514.     */
  515.    protected void drawFrame(Graphics g, int x, int y, int w, int h, 
  516.                 int type, int thickness, int margin)
  517.    { 
  518.       if(thickness <= 0)
  519.      return;
  520.  
  521.       if (frameDark1 == null) {
  522.      // create frame colors from background
  523.      frameDark1 = FunScrollColorSupport.darker(getBackground(), .50);
  524.      frameDark2 = FunScrollColorSupport.darker(getBackground(), .10);
  525.      frameBright = FunScrollColorSupport.brighter(getBackground(), .50);
  526.       }
  527.       
  528.       switch (type) {
  529.       case ShadowOut:
  530.      for(int i=0;i<thickness;i++) {
  531.         // top left
  532.         g.setColor(frameBright);
  533.         drawTopLeftLines(g, x, y, w, h, i, margin);
  534.         // bottom right
  535.         g.setColor(frameDark1);
  536.         drawBottomRightLines(g, x, y, w, h, i, margin);
  537.      }
  538.      break;
  539.       case ShadowEtchedIn:
  540.      for(int i=0;i<thickness;i++) {
  541.         // top left
  542.         if(i == 0)
  543.            g.setColor(frameDark1);
  544.         else if (i == thickness-1)
  545.            g.setColor(frameBright);
  546.         else
  547.            g.setColor(frameDark2);
  548.         drawTopLeftLines(g, x, y, w, h, i, margin);
  549.         
  550.         // bottom right
  551.         if(i == 0)
  552.            g.setColor(frameBright);
  553.         else if (i == thickness-1)
  554.            g.setColor(frameDark1);
  555.         else
  556.            g.setColor(frameDark2);
  557.         drawBottomRightLines(g, x, y, w, h, i, margin);
  558.      }
  559.      break;
  560.       case ShadowEtchedOut:
  561.      for(int i=0;i<thickness;i++) {
  562.         // top left
  563.         if(i == 0)
  564.            g.setColor(frameBright);
  565.         else if (i == thickness-1)
  566.            g.setColor(frameDark1);
  567.         else
  568.            g.setColor(getBackground());
  569.         drawTopLeftLines(g, x, y, w, h, i, margin);
  570.         
  571.         // bottom right
  572.         if(i == 0)
  573.            g.setColor(frameDark1);
  574.         else if (i == thickness-1)
  575.            g.setColor(frameBright);
  576.         else 
  577.            g.setColor(getBackground());
  578.         drawBottomRightLines(g, x, y, w, h, i, margin);
  579.      }
  580.      break;
  581.       default:            // ShadowIn (default)
  582.      for(int i=0;i<thickness;i++) {
  583.         // top left
  584.         g.setColor(frameDark1);
  585.         drawTopLeftLines(g, x, y, w, h, i, margin);
  586.         // bottom right
  587.         g.setColor(frameBright);
  588.         drawBottomRightLines(g, x, y, w, h, i, margin);
  589.      }
  590.       }
  591.       // reset background color
  592.       g.setColor(getBackground());
  593.    }
  594.  
  595.    void drawTopLeftLines(Graphics g,
  596.              int x, int y, int w, int h, int i, int margin)
  597.    {
  598.       g.drawLine(x+margin+i, y+margin+i, x+w-margin-i-1, y+margin+i);
  599.       g.drawLine(x+margin+i, y+margin+i, x+margin+i, y+h-margin-i-1);
  600.    }
  601.  
  602.    void drawBottomRightLines(Graphics g,
  603.                int x, int y, int w, int h, int i, int margin)
  604.    {
  605.       g.drawLine(x+margin+i, y+h-margin-i-1, x+w-margin-i-1, y+h-margin-i-1);
  606.       g.drawLine(x+w-margin-i-1, y+margin+i, x+w-margin-i-1, y+h-margin-i-1);
  607.    }
  608.    
  609.    /**
  610.     * Update a frame of animation
  611.     *
  612.     */
  613.    public void update(Graphics g)
  614.    {
  615.       if (!initiated) {
  616.      paintLoadMessage(g);
  617.      return;
  618.       }
  619.           
  620.       long tm = 0;
  621.       if (debug)
  622.      tm = System.currentTimeMillis();
  623.  
  624.       // get size of applet 
  625.       Dimension d = size();
  626.          
  627.       // Create the offscreen graphics context if required
  628.       if((offImage == null) ||
  629.      (d.width != offSize.width) ||
  630.      (d.height != offSize.height)) {
  631.  
  632.      // create off-screen graphics context
  633.      offSize = d;
  634.      offImage = createImage(d.width, d.height);
  635.      offGraphics = offImage.getGraphics();
  636.  
  637.      // init text area size
  638.      textSize = new Dimension(d.width-(2*(frameWidth+frameMargin)),
  639.                   d.height-(2*(frameWidth+frameMargin)));
  640.      
  641.      // reset Animated Text item
  642.      currentText.reset(frameMargin+frameWidth,
  643.                d.width, d.height, offGraphics);
  644.  
  645.      
  646.      // paint frame
  647.      offGraphics.setColor(getBackground());
  648.      offGraphics.fillRect(0, 0, d.width, d.height);
  649.      drawFrame(offGraphics,
  650.            0, 0, d.width, d.height,
  651.            frameType, frameWidth, frameMargin);
  652.  
  653.      // from here on just manipulate the text area, using a
  654.      // clip rectangle.
  655.      offGraphics.clipRect(frameMargin+frameWidth, frameMargin+frameWidth,
  656.                   textSize.width, textSize.height);
  657.       }
  658.  
  659.       // reset text background
  660.       offGraphics.setColor(getBackground());
  661.       offGraphics.fillRect(frameMargin+frameWidth, frameMargin+frameWidth,
  662.                textSize.width, textSize.height);
  663.  
  664.       if ((bgImage != null) && 
  665.       (mediaTracker.statusID(0, true) & MediaTracker.COMPLETE) != 0) {
  666.      // background image loaded; paint it
  667.      paintTiledImage(offGraphics, bgImage, frameMargin+frameWidth,
  668.              textSize.width, textSize.height);
  669.       }
  670.  
  671.       // animate text
  672.       animate(offGraphics, frameMargin+frameWidth, d.width, d.height);
  673.       
  674.       // paint the image onto the screen
  675.       g.drawImage(offImage, 0, 0, null);
  676.       
  677.       dbg("time for update():" + (System.currentTimeMillis() - tm));
  678.    }
  679.  
  680.    /**
  681.     * Run the loop. This method is called by class Thread.
  682.     */
  683.    public void run() {
  684.       
  685.       if (Thread.currentThread() == thread) {
  686.      thread.setPriority(Thread.MIN_PRIORITY);
  687.      // init parameters (once)
  688.      if (!initiated) {
  689.         // immediately paint the "Loading.." message
  690.         Graphics g = getGraphics();
  691.         paintLoadMessage(g);
  692.         getToolkit().sync(); 
  693.         initParameters();
  694.      }
  695.       }
  696.       
  697.       while (Thread.currentThread() == thread) {
  698.      // Repaint. I.e call update() to go trough one frame of
  699.      // animation.
  700.      repaint();
  701.      
  702.      // Delay depending on how far we are behind (to assure
  703.          // we really delay as much as requested).
  704.      try {
  705.         threadStartTime += threadDelay;
  706.         int delay = (int) Math.max(
  707.            threadDelay/2, threadStartTime - System.currentTimeMillis());
  708.         dbg("Sleep:" + delay);
  709.         Thread.sleep(delay);
  710.      } catch (InterruptedException e) {
  711.         break;
  712.      }
  713.      
  714.      // reload data from URL if required
  715.      if (lineData != null && updateInterval > 0) {
  716.         if (animateCount >= updateInterval) {
  717.            // reaload line data from URL
  718.            dbg("Re-init data from URL");
  719.            animateCount = 0;
  720.            Vector lineVector = new Vector();
  721.            initLineParametersFromInputURL(
  722.           lineData, lineVector, urlStrings);
  723.            createAnimatedTexts(lineVector, font,
  724.                    getForeground(), getBackground(),
  725.                    dx, dy, delim);
  726.         }
  727.      }
  728.       }
  729.    }
  730.    
  731.    /**
  732.     * Start the applet by forking an animation thread.
  733.     */
  734.    public void start() {
  735.       repaint();
  736.       if (thread == null) {
  737.      // create new animate thread (using thread-group saved in init)
  738.      if (threadGroup != null)
  739.         thread = new Thread(threadGroup, this);
  740.      else
  741.         thread = new Thread(this);
  742.      thread.start();
  743.       }
  744.       // remember the thread start time
  745.       threadStartTime = System.currentTimeMillis();
  746.    }
  747.    
  748.    /**
  749.     * Stop the applet. The thread will exit because run() exits.
  750.     */
  751.    public void stop() {
  752.       thread = null;
  753.    }
  754.    
  755.    /**
  756.     * Take care of mouse-up event to handle Suspend/Resume
  757.     * and to show about info.
  758.     */
  759.    public boolean mouseUp(Event evt, int x, int y) {
  760.  
  761.       if ((evt.modifiers & Event.SHIFT_MASK) != 0) {
  762.      showAbout();
  763.      return true;
  764.       }
  765.       
  766.       String urlString = null;
  767.       if (currentTextIndex < urlStrings.size())
  768.      urlString = (String) urlStrings.elementAt(currentTextIndex);
  769.       
  770.       // handle Suspend/Resume
  771.       // Note: Netscape 3.0 doesnt like Thread.suspend() so, im
  772.       //       now existing the thread instead...
  773.       if (suspended || thread == null) {
  774.      start();
  775.      suspended = false;
  776.       }
  777.       else if (urlString == null) {
  778.      stop();
  779.      suspended = true;
  780.       }
  781.       
  782.       if (suspended)
  783.      // show version when suspended (sneak promotion ;-)
  784.      showStatus(getAppletInfo() + " - Click to resume.");
  785.       else {
  786.      if (urlString != null)
  787.         // show document as specified in urlString
  788.         showDocument(urlString);
  789.      else
  790.         // tell about about popup...
  791.         showStatus(getAppletInfo() + " - Shift-click for info...");
  792.       }
  793.  
  794.       return true;
  795.    }
  796.  
  797.    /**
  798.     * Take care of mouse-enter event to handle show URL (if specified)
  799.     */
  800.    public boolean mouseEnter(Event evt, int x, int y) {
  801.       showUrl();
  802.       return true;
  803.    }
  804.  
  805.    /**
  806.     * Display "about" popup frame
  807.     */
  808.    void showAbout() {
  809.       FunScrollAbout about = new FunScrollAbout(getAppletInfo());
  810.       
  811.       about.appendText("\t" + getAppletInfo() + "\n\n");
  812.       about.appendText("Copyright (c) 1996 by " +
  813.                "Jan Andersson, Torpa Konsult AB.\n\n");
  814.       about.appendText("Info, updates and documentation at " +
  815.                      sourceLocation + "\n\n");
  816.       
  817.       about.appendText("Applet information:\n");
  818.  
  819.       about.appendText(" Document base: " + getDocumentBase()+"\n");
  820.       about.appendText(" Code base: " + getCodeBase()+"\n\n");
  821.  
  822.       about.appendText(" Applet parameters:\n");
  823.       about.appendText("  width = " + getParameter("WIDTH")+"\n");
  824.       about.appendText("  height = " + getParameter("HEIGHT")+"\n\n");
  825.  
  826.       // Display parameter info
  827.       about.appendText(" Message lines (line<n> parameters):\n");
  828.       for (int i = 0; i < noOfTexts; i++) {
  829.      FunScrollAnimatedText txt = (FunScrollAnimatedText)
  830.         animatedTexts.elementAt(i);
  831.      about.appendText("  line" + i +" = " +
  832.               txt.getUnparsedTextLine() + "\n");
  833.      about.appendText("  url" + i +" = ");
  834.      String urlString = null;
  835.      if (i < urlStrings.size()) 
  836.         urlString = (String) urlStrings.elementAt(i);
  837.      about.appendText(urlString + "\n");
  838.       }
  839.       
  840.       about.appendText("\n Other parameters:\n");
  841.       String params[][] = getParameterInfo();
  842.       for (int i = 2; i < params.length; i++) {
  843.      String parInfo = "  " + params[i][0] + " = " +
  844.         getParameter(params[i][0]);
  845.      if (parInfo.length() <= 17)
  846.         parInfo += "\t";
  847.      about.appendText(parInfo + "\t [" + params[i][2] + "]\n");
  848.       }
  849.       
  850.       about.show();
  851.    }
  852.  
  853.    /**
  854.     * Display current url in status line.
  855.     */
  856.    void showUrl() {
  857.       // display current url if specified
  858.       if (urlStrings != null && currentTextIndex < urlStrings.size()) {
  859.      String urlString =
  860.         (String) urlStrings.elementAt(currentTextIndex);
  861.      if (urlString != null) {
  862.         String tmp = urlString.toUpperCase();
  863.         int tIndex = tmp.indexOf("TARGET=");
  864.         if (tIndex > 0) 
  865.            urlString = urlString.substring(0, tIndex);
  866.         showStatus(urlString);
  867.      }
  868.      else
  869.         showStatus("");
  870.       }
  871.    }
  872.    
  873.    /**
  874.     * Show document as specified in URL string
  875.     */
  876.    void showDocument(String urlString) {
  877.       // check if target option specified in URL string
  878.       String target = null;
  879.       String tmp = urlString.toUpperCase();
  880.       int tIndex = tmp.indexOf("TARGET=");
  881.       if (tIndex > 0) {
  882.      target = urlString.substring(tIndex+7);
  883.      urlString = urlString.substring(0, tIndex);
  884.      target = target.trim();
  885.      dbg("target:" + target);
  886.       }
  887.  
  888.       if (target == null)
  889.      // use target provided as parameter
  890.      target = urlTarget;
  891.  
  892.       // try to get url in context of current document
  893.       URL url = null;
  894.       try {
  895.          url = new URL(getDocumentBase(), urlString);
  896.       }
  897.       catch (MalformedURLException e) {
  898.          showStatus(e.getMessage());
  899.          url = null;
  900.       }
  901.       if (url == null) {
  902.          // next, try to get url directly 
  903.          try {
  904.             url = new URL(urlString);
  905.          }
  906.      catch (MalformedURLException e) {
  907.             showStatus(e.getMessage());
  908.             url = null;
  909.          }
  910.       }
  911.       
  912.       // Load URL, using showDocument()
  913.       if (url != null) {
  914.      showStatus("Loading: " + urlString + "...");
  915.      if (target == null)
  916.         getAppletContext().showDocument(url);
  917.      else
  918.         getAppletContext().showDocument(url, target);
  919.       }
  920.    }
  921.    
  922.    /**
  923.     * Simple debug...
  924.     */
  925.    static public void dbg(String str) {
  926.       if (debug) {
  927.      System.out.println("Debug: " + str);
  928.      System.out.flush();
  929.       }
  930.    }  
  931. }
  932.  
  933.  
  934.  
  935.  
  936. /*
  937.  * Copyright (c) 1995 by Jan Andersson, Torpa Konsult AB.
  938.  *
  939.  * Permission to use, copy, and distribute this software for
  940.  * NON-COMMERCIAL purposes and without fee is hereby granted
  941.  * provided that this copyright notice appears in all copies.
  942.  */
  943.  
  944.  
  945. /**
  946.  * FunScroll "about" popup.
  947.  *
  948.  * @version 1.1 96/07/17
  949.  * @author  Jan Andersson (janne@torpa.se)
  950.  */
  951. class FunScrollAbout extends Frame
  952. {
  953.    
  954.    static final int rows = 27;
  955.    static final int cols = 70;
  956.     
  957.    TextArea info;
  958.    Button close;
  959.  
  960.    /**
  961.     * Create About popup frame
  962.     */
  963.    FunScrollAbout(String label) {
  964.       super(label);
  965.  
  966.       add("Center", info = new TextArea(rows, cols));
  967.       info.setEditable(false);
  968.       //info.setBackground(Color.white);
  969.  
  970.       Panel buttons = new Panel();
  971.       add("South", buttons);
  972.       buttons.add(close = new Button("Close"));
  973.       
  974.       pack();
  975.    }
  976.  
  977.    /**
  978.     * Show frame
  979.     */
  980.    public void show() {
  981.       info.select(0,0);
  982.       super.show();
  983.    }
  984.  
  985.    /**
  986.     * Append text
  987.     */
  988.    void appendText(String s) {
  989.       info.appendText(s);
  990.    }
  991.    
  992.    /**
  993.     * Handle window destroy event
  994.     */
  995.    public boolean handleEvent(Event e) {
  996.       if (e.id == Event.WINDOW_DESTROY) {
  997.      dispose();
  998.      return true;
  999.       }
  1000.       return super.handleEvent(e);
  1001.    }
  1002.  
  1003.    /**
  1004.     * Handle "close" button action
  1005.     */
  1006.    public boolean action(Event e, Object arg) {
  1007.       if (e.target == close) {
  1008.      //hide();
  1009.      dispose();
  1010.      return true;
  1011.       }
  1012.       return false;
  1013.    }
  1014. }
  1015.  
  1016.  
  1017.  
  1018.  
  1019.  
  1020.  
  1021.  
  1022.  
  1023. /*
  1024.  * Copyright (c) 1995 by Jan Andersson, Torpa Konsult AB.
  1025.  *
  1026.  * Permission to use, copy, and distribute this software for
  1027.  * NON-COMMERCIAL purposes and without fee is hereby granted
  1028.  * provided that this copyright notice appears in all copies.
  1029.  */
  1030.  
  1031. /**
  1032.  * FunScroll Animated Text(s)
  1033.  *
  1034.  * @version 1.8 96/08/31
  1035.  * @author  Jan Andersson (janne@torpa.se)
  1036.  */
  1037. class FunScrollAnimatedText
  1038. {
  1039.                 // states:
  1040.    static final int START = 0;    // start sequence
  1041.    static final int SHOW = 1;    // show sequence
  1042.    static final int END = 2;    // end sequence
  1043.    static final int DONE = 3;    // done sequence
  1044.    int state = START;        // animate state
  1045.    FunScroll appl;        // FunScroll applet
  1046.    FunScrollTextAttr attr;    // attributes
  1047.    String unparsedText;        // unparsed text line
  1048.    String[] lines;        // lines of text
  1049.    protected int[] lineWidths;  // how wide each line is
  1050.    int noOfLines = 1;        // number of lines
  1051.    char chars[];        // the characters
  1052.    int noOfChars;        // number of characters
  1053.    int xPos[];            // the x positions
  1054.    int yPos[];            // the y positions
  1055.    boolean visible[];        // flags set to true if character visible
  1056.    int delayCount = 0;        // used to delay for a while
  1057.    int offset;            // the offset (x and y)
  1058.    int width;            // the applet width
  1059.    int height;            // the applet height
  1060.    int textHeight;        // text height
  1061.    int lineHeight;        // text line height
  1062.    Color bg;            // background color
  1063.    Color fg;            // foreground color
  1064.    Color darkBg;        // dark background
  1065.    Color lightDarkBg;        // lightdark background
  1066.    Color brightBg;        // bright background
  1067.    Color brightFg;        // bright foreground
  1068.    
  1069.    Font font;            // font
  1070.    FontMetrics fontMetrics;    // font metrics
  1071.    int ascent;            // font ascent
  1072.    int descent;            // font descent
  1073.    int leading;            // font leading
  1074.    int maxWidth;        // max width
  1075.    int sinDegree;        // used for sin-wave text
  1076.    int xStart;            // starting X pos
  1077.    int yStart;            // starting Y pos
  1078.    int dx;            // x distance to move
  1079.    int dy;            // y distance to move
  1080.  
  1081.    public FunScrollAnimatedText(FunScroll appl, String line,
  1082.                 Font font, Color fg, Color bg,
  1083.                 int dx, int dy, String delim)
  1084.    {
  1085.       this.appl = appl;
  1086.       this.font = font;
  1087.       this.fg = fg;
  1088.       this.bg = bg;
  1089.       this.dy = dy;
  1090.       this.dx = dx;
  1091.       this.unparsedText = line;
  1092.       
  1093.       // parse message line and init attributes
  1094.       attr = new FunScrollTextAttr(line, delim);
  1095.  
  1096.       appl.dbg("Parsed Attributes:");
  1097.       appl.dbg("         msg:" + attr.msg());
  1098.       appl.dbg(" startScroll:" + attr.startScroll());
  1099.       appl.dbg("   endScroll:" + attr.endScroll());
  1100.       appl.dbg("   showDelay:" + attr.showDelay());
  1101.       appl.dbg("    endDelay:" + attr.endDelay());
  1102.       appl.dbg("       style:" + attr.style());
  1103.       appl.dbg("   drawStyle:" + attr.drawStyle());
  1104.       appl.dbg("      color:" + attr.color());
  1105.       appl.dbg("dy:" + dy + " dx:" + dx);
  1106.       
  1107.       // get color attribute (if specified)
  1108.       if (attr.color() != null) 
  1109.      this.fg = appl.readColor(attr.color(), fg);
  1110.       appl.dbg("      color:" + fg);
  1111.  
  1112.       // init font stuff
  1113.       fontMetrics = appl.getFontMetrics(font);
  1114.       ascent = fontMetrics.getAscent();
  1115.       descent = fontMetrics.getDescent();
  1116.       leading = fontMetrics.getLeading();
  1117.       
  1118.       // init character related varaiables
  1119.       String msg = attr.msg();
  1120.       Vector linesOftext = new Vector();
  1121.       noOfChars = msg.length();
  1122.       chars = new char[noOfChars];
  1123.       msg.getChars(0, noOfChars, chars, 0);
  1124.       xPos = new int[noOfChars];
  1125.       yPos = new int[noOfChars];
  1126.       visible = new boolean[noOfChars];
  1127.  
  1128.       textHeight = fontMetrics.getHeight();
  1129.       if (attr.style() == FunScrollTextAttr.NERVOUS ||
  1130.       attr.style() == FunScrollTextAttr.SINEWAVE)
  1131.      // need some extra space here!
  1132.      textHeight += 4;
  1133.       lineHeight = fontMetrics.getHeight();
  1134.       
  1135.       int currXPos = 0;
  1136.       int currYPos = ascent;
  1137.       boolean escape = false;
  1138.       boolean newLine = false;
  1139.       int lineStartIndex = 0;
  1140.       int i;
  1141.       for (i = 0; i < noOfChars; i++) {
  1142.      if (escape) {
  1143.         // we already have an escape character
  1144.         if (chars[i] == 'n') {
  1145.            // got "\n" - line break; i.e line really consists
  1146.            // of more than one line
  1147.            chars[i-1] = ' ';
  1148.            chars[i] = ' ';
  1149.            newLine = true;
  1150.         }
  1151.         escape = false;
  1152.      }
  1153.      else if (chars[i] == '\\') {
  1154.         // escaped characted; wait for next character
  1155.         escape = true;
  1156.      }
  1157.      else {
  1158.         if (newLine) {
  1159.            // get line of text
  1160.            linesOftext.addElement(
  1161.           msg.substring(lineStartIndex, i-2));
  1162.            lineStartIndex = i;
  1163.            // we have a new line
  1164.            noOfLines++;
  1165.            textHeight += fontMetrics.getHeight();
  1166.            currXPos = fontMetrics.charsWidth(chars, 0, i);
  1167.            currYPos += lineHeight; //descent + ascent;
  1168.            newLine = false;
  1169.         }
  1170.         if (i > 0)
  1171.            xPos[i] = fontMetrics.charsWidth(chars, 0, i) - currXPos;
  1172.         else
  1173.            xPos[i] = currXPos;
  1174.         
  1175.         maxWidth = Math.max(maxWidth, xPos[i]);
  1176.         yPos[i] = currYPos;
  1177.      }
  1178.       }
  1179.       if (i > lineStartIndex) 
  1180.      // get line of text
  1181.      linesOftext.addElement(
  1182.         msg.substring(lineStartIndex, i));
  1183.  
  1184.       // init array of lines and line widths
  1185.       lineWidths = new int[noOfLines];
  1186.       lines = new String[noOfLines];
  1187.       for (i=0; i < noOfLines; i++) {
  1188.      lines[i] = (String)linesOftext.elementAt(i);
  1189.      lineWidths[i] = fontMetrics.stringWidth(lines[i]);
  1190.       }
  1191.    }
  1192.  
  1193.    /**
  1194.     * Reset array of x positions 
  1195.     */
  1196.    void resetX()
  1197.    {
  1198.       int currXPos = 0;
  1199.       int currYPos = (noOfChars > 0) ? yPos[0] : 0;
  1200.       for (int i = 0; i < noOfChars; i++) {
  1201.      if (currYPos != yPos[i]) {
  1202.         // new line
  1203.         currXPos = fontMetrics.charsWidth(chars, 0, i);
  1204.         currYPos = yPos[i];
  1205.      }
  1206.      if (i > 0)
  1207.         xPos[i] = fontMetrics.charsWidth(chars, 0, i) - currXPos;
  1208.      else
  1209.         xPos[i] = currXPos;
  1210.       }
  1211.    }
  1212.    
  1213.  
  1214.    /**
  1215.     * Reset width and height
  1216.     */
  1217.    void reset(int offset, int width, int height, Graphics g)
  1218.    {
  1219.       this.offset = offset;
  1220.       this.width = width;
  1221.       this.height = height;
  1222.       int scroll = attr.startScroll();
  1223.       switch (scroll) {
  1224.       case FunScrollTextAttr.NONE:
  1225.      xStart = (width-maxWidth)/2;
  1226.      yStart = (height-textHeight)/2;
  1227.      break;
  1228.       case FunScrollTextAttr.LEFT:
  1229.      xStart = width-dx-offset;
  1230.      yStart = (height-textHeight)/2;
  1231.      break;
  1232.       case FunScrollTextAttr.RIGHT:
  1233.      xStart = dx+offset;
  1234.      yStart = (height-textHeight)/2;
  1235.      break;
  1236.       case FunScrollTextAttr.UP:
  1237.      xStart = (width-maxWidth)/2;
  1238.      yStart = height-descent-offset;
  1239.      break;
  1240.       case FunScrollTextAttr.DOWN:
  1241.      xStart = (width-maxWidth)/2;
  1242.      yStart = 0-textHeight+offset;
  1243.      break;
  1244.       }
  1245.  
  1246.       // adjust for offset
  1247.       width -= 2*offset;
  1248.       height -= 2*offset;
  1249.  
  1250.       // Reset array of x positions
  1251.       resetX();
  1252.       
  1253.       // reset state
  1254.       state = START;
  1255.       FunScroll.dbg("State: START");
  1256.  
  1257.       // reset font and foreground
  1258.       g.setFont(font);
  1259.       g.setColor(fg);
  1260.    }
  1261.  
  1262.    public String getUnparsedTextLine()
  1263.    {
  1264.       return unparsedText;
  1265.    }
  1266.    
  1267.    /**
  1268.     * Update. I.e move and paint.
  1269.     */
  1270.    boolean update(Graphics g) 
  1271.    {
  1272.       move();
  1273.       paint(g);
  1274.       if (state == DONE && delayCount <= 0)
  1275.      return true;        // we are done!
  1276.       else
  1277.      return false;
  1278.    }
  1279.  
  1280.    /**
  1281.     * Move characters
  1282.     */
  1283.    void move()
  1284.    {
  1285.       boolean switchState = false;
  1286.       int scroll = FunScrollTextAttr.NONE;
  1287.       switch (state) {
  1288.      case START:
  1289.         // start sequence
  1290.         scroll = attr.startScroll();
  1291.         if (scroll == FunScrollTextAttr.NONE) {
  1292.            // no animation;     just switch state
  1293.            switchState = true;
  1294.         }
  1295.         else {
  1296.            // some kind of animation; check if all characters displ.
  1297.           if (textDisplayed(scroll)) {
  1298.           // yupp; switch state
  1299.           switchState = true;
  1300.            }
  1301.         }
  1302.  
  1303.         if (!switchState) {
  1304.            // just move text (scroll)
  1305.            moveText(scroll);
  1306.            updateVisible(scroll);
  1307.            break;
  1308.         }
  1309.         
  1310.         // switch state
  1311.         updateVisible(scroll);
  1312.         state = SHOW;
  1313.         FunScroll.dbg("State: SHOW");
  1314.         delayCount = attr.showDelay();
  1315.         // fall trough!
  1316.         
  1317.      case SHOW:
  1318.         // show sequence
  1319.         if (--delayCount >= 0) {
  1320.            // delay. I.e break out
  1321.            break;
  1322.         }
  1323.         
  1324.         // switch state
  1325.         state = END;
  1326.         FunScroll.dbg("State: END");
  1327.         // fall trough!
  1328.  
  1329.       case END:
  1330.         // end sequence
  1331.         // check if all characters still visible
  1332.         if (updateVisible(attr.endScroll()) == 0 ||
  1333.         attr.endScroll() == FunScrollTextAttr.NONE) {
  1334.            // none visible or no end animation; switch state
  1335.            state = DONE;
  1336.            FunScroll.dbg("State: DONE");
  1337.            delayCount = attr.endDelay();
  1338.            return;
  1339.         }
  1340.         else {
  1341.            moveText(attr.endScroll());
  1342.         }
  1343.         break;
  1344.  
  1345.      case DONE:
  1346.         // done sequence; just delay
  1347.         delayCount--;
  1348.         break;
  1349.       }
  1350.    }
  1351.  
  1352.    /**
  1353.     * Return true if (all) text is displayed
  1354.     */
  1355.    boolean textDisplayed(int scroll)
  1356.    {
  1357.       switch (scroll) {
  1358.      case FunScrollTextAttr.LEFT:
  1359.         // scrolling left
  1360.         if (maxWidth > width) {
  1361.            // text is wider that applet width
  1362.            if (maxWidth+xStart < width-4*dx)
  1363.           return true;
  1364.         }
  1365.         else {
  1366.            int appletMidPoint = width/2;
  1367.            int textMidPoint = xStart+maxWidth/2;
  1368.            if (textMidPoint <= appletMidPoint)
  1369.           return true;
  1370.         }
  1371.         break;
  1372.         
  1373.      case FunScrollTextAttr.RIGHT:
  1374.         // scrolling right
  1375.         if (maxWidth > width) {
  1376.            // text is wider that applet width
  1377.            if (xPos[0]+xStart > 4*dx)
  1378.           return true;
  1379.         }
  1380.         else {
  1381.            int appletMidPoint = width/2;
  1382.            int textMidPoint = xStart+maxWidth/2;
  1383.            if (textMidPoint >= appletMidPoint)
  1384.           return true;
  1385.         }
  1386.         break;
  1387.         
  1388.      case FunScrollTextAttr.UP:
  1389.         // scrolling up
  1390.         if (yStart <= (height-textHeight)/2-descent)
  1391.            return true;
  1392.         break;
  1393.         
  1394.      case FunScrollTextAttr.DOWN:
  1395.         // scrolling down
  1396.         if (yStart >= (height-textHeight)/2-descent) 
  1397.            return true;
  1398.         break;
  1399.       }
  1400.       return false;
  1401.    }
  1402.    
  1403.    /**
  1404.     * update array with flags if characters are visible. Return
  1405.     * number of visible characters.
  1406.     */
  1407.    int updateVisible(int scroll)
  1408.    {
  1409.       int visibleCount = 0;
  1410.       
  1411.       for (int i = 0; i < noOfChars; i++) {
  1412.      visible[i] = (xPos[i]+xStart > offset &&
  1413.                xPos[i]+xStart < width-offset &&
  1414.                yPos[i]+yStart+lineHeight > offset  &&
  1415.                yPos[i]+yStart-lineHeight < height-offset);
  1416.      if (visible[i])
  1417.         visibleCount++;
  1418.       }
  1419.       // special treatment of explode animation
  1420.       if (scroll == FunScrollTextAttr.EXPLODE) {
  1421.      // if only 5 or less chars visible (per line) consider this as done
  1422.      if (visibleCount <= (noOfLines*5))
  1423.         visibleCount = 0;
  1424.       }
  1425.       return visibleCount;
  1426.    }
  1427.       
  1428.    void moveText(int scroll)
  1429.    {
  1430.       switch (scroll) {
  1431.      case FunScrollTextAttr.LEFT:
  1432.         xStart -= dx;
  1433.         break;
  1434.      case FunScrollTextAttr.RIGHT:
  1435.         xStart += dx;
  1436.         break;
  1437.      case FunScrollTextAttr.UP:
  1438.         yStart -= dy;
  1439.         break;
  1440.      case FunScrollTextAttr.DOWN:
  1441.         yStart += dy;
  1442.         break;
  1443.      case FunScrollTextAttr.EXPLODE:
  1444.         moveExplodeText();
  1445.         break;
  1446.       }
  1447.    }
  1448.  
  1449.    /**
  1450.     * Move exploding text
  1451.     */
  1452.    void moveExplodeText() {
  1453.       int mid = noOfChars/2;
  1454.       float maxDist = maxWidth/4;
  1455.       for (int i = 0; i < mid; i++) {
  1456.      // move to the left
  1457.      float percentOfMax = (float)(mid-i)/mid;
  1458.      xPos[i] -= (int) Math.max((percentOfMax * maxDist), 2.0);
  1459.       }
  1460.       for (int i = mid; i < noOfChars; i++) {
  1461.      // move to the right
  1462.      float percentOfMax = (float) (i-mid)/mid;
  1463.      xPos[i] += (int) Math.max((percentOfMax * maxDist), 2.0);
  1464.       }
  1465.    }
  1466.    
  1467.    /**
  1468.     * Paint characters
  1469.     */
  1470.    void paint(Graphics g)
  1471.    {
  1472.       // set foreground color
  1473.       g.setColor(fg);
  1474.       
  1475.       switch (attr.style()) {
  1476.       case FunScrollTextAttr.SINEWAVE:
  1477.      paintSineWave(g);
  1478.      break;
  1479.       case FunScrollTextAttr.NERVOUS:
  1480.      paintNervous(g);
  1481.      break;
  1482.       default:
  1483.      if (attr.endScroll() == FunScrollTextAttr.EXPLODE)
  1484.         paintExplode(g);
  1485.      else
  1486.         paintNormal(g);
  1487.      break;
  1488.       }
  1489.    }
  1490.    
  1491.    /**
  1492.     * Paint "exploding" text line
  1493.     */
  1494.    void paintExplode(Graphics g) {
  1495.       for (int i = 0; i < noOfChars; i++) {
  1496.      if (visible[i]) 
  1497.         drawNormalChar(g, i);
  1498.       }
  1499.    }
  1500.  
  1501.    /**
  1502.     * Paint normal text line
  1503.     */
  1504.    void paintNormal(Graphics g) {
  1505.       switch (attr.drawStyle()) {
  1506.       case attr.ENGRAVE:
  1507.       case attr.EMBOSS:
  1508.      // pain emboss or engrave line
  1509.      paintEmbossEngrave(g);
  1510.      break;
  1511.       case attr.SHADOW:
  1512.      // pain shadowed line
  1513.      paintShadow(g);
  1514.      break;
  1515.       case attr.NONE:
  1516.      // draw normal line(s)
  1517.      for (int i=0; i < noOfLines; i++) {
  1518.         drawAlignedString(g, i,
  1519.              xStart, yStart + ascent + (lineHeight*i));
  1520.      }
  1521.      break;
  1522.       }
  1523.    }
  1524.  
  1525.    /**
  1526.     * Paint emboss/engrave text line
  1527.     */
  1528.    void paintEmbossEngrave(Graphics g) {
  1529.       // init colors (first time)
  1530.       if (darkBg == null) {
  1531.      darkBg = FunScrollColorSupport.darker(bg, 0.5);
  1532.      lightDarkBg = FunScrollColorSupport.darker(bg, 0.5 - (0.5/2));
  1533.      brightBg = FunScrollColorSupport.brighter(bg, 0.5);
  1534.       }
  1535.       
  1536.       int drawStyle = attr.drawStyle();
  1537.       Color upperLeftColor = (drawStyle == attr.ENGRAVE) ? darkBg : brightBg;
  1538.       Color upperRightColor = (drawStyle == attr.ENGRAVE) ? brightBg : darkBg;
  1539.       Color mainColor = (drawStyle == attr.ENGRAVE) ? lightDarkBg : bg;
  1540.       int depth = 1;        // hardkoded ;-(
  1541.       
  1542.       for (int i=0; i < noOfLines; i++) {
  1543.      drawAlignedString(g, i,
  1544.               xStart, yStart + ascent + (lineHeight*i));
  1545.  
  1546.      // upper left edge
  1547.      g.setColor(upperLeftColor);
  1548.      drawAlignedString(g, i,
  1549.               xStart,
  1550.               yStart + ascent + (lineHeight*i) - depth);
  1551.      
  1552.      // lower right edge
  1553.      g.setColor(upperRightColor);
  1554.      drawAlignedString(g, i,
  1555.               xStart + depth*2,
  1556.               yStart + ascent + (lineHeight*i) + depth);
  1557.      
  1558.      // main body of the character
  1559.      g.setColor(mainColor);
  1560.      drawAlignedString(g, i,
  1561.               xStart + depth,
  1562.               yStart + ascent + (lineHeight*i));
  1563.       }
  1564.    }
  1565.  
  1566.    /**
  1567.     * Paint emboss/engrave text line
  1568.     */
  1569.    void paintShadow(Graphics g) {
  1570.       int shadowOffset = 4;
  1571.       if (brightFg == null) 
  1572.      brightFg = FunScrollColorSupport.brighter(fg, 0.75);
  1573.       for (int i=0; i < noOfLines; i++) {
  1574.      g.setColor(brightFg);
  1575.      drawAlignedString(g, i,
  1576.               xStart + shadowOffset,
  1577.               yStart + ascent + (lineHeight*i) + shadowOffset);
  1578.      g.setColor(fg);
  1579.      drawAlignedString(g, i,
  1580.                xStart,
  1581.                yStart + ascent + (lineHeight*i));
  1582.       }
  1583.    }
  1584.  
  1585.    /**
  1586.     * draw aligned string
  1587.     */
  1588.    void drawAlignedString(Graphics g, int index, int x, int y)
  1589.    {
  1590.       switch(attr.align()) {
  1591.       case attr.LEFT:
  1592.      break;
  1593.       case attr.RIGHT:
  1594.      x = width - x - lineWidths[index];
  1595.      break;
  1596.       case attr.CENTER:
  1597.      x = x + (maxWidth - lineWidths[index])/2;
  1598.      break;
  1599.       }
  1600.       g.drawString(lines[index], x, y);
  1601.    }
  1602.    
  1603.    
  1604.    /**
  1605.     * Paint sine-wave text line
  1606.     */
  1607.    void paintSineWave(Graphics g) {
  1608.       int currYPos = (noOfChars > 0) ? yPos[0] : 0;
  1609.       int degree = sinDegree;
  1610.       for (int i = noOfChars-1; i >= 0; i--) {
  1611.      if (currYPos != yPos[i]) {
  1612.         // new line
  1613.         currYPos = yPos[i];
  1614.         degree = sinDegree;
  1615.      }
  1616.      if (visible[i]) {
  1617.         // draw character
  1618.         int sinHeight = lineHeight/3;
  1619.         int y = (int) (Math.sin(degree*3.1414/180) * sinHeight);
  1620.         drawChar(g, i, xPos[i]+xStart, yPos[i]+yStart+y);
  1621.      }
  1622.      degree -= 15;
  1623.      if (degree <= 0)
  1624.         degree = 360;
  1625.       }
  1626.       sinDegree -= 15;
  1627.       if (sinDegree <= 0)
  1628.      sinDegree = 360;
  1629.    }
  1630.  
  1631.    /**
  1632.     * Paint nervous text line
  1633.     */
  1634.    void paintNervous(Graphics g) {
  1635.       for (int i = 0; i < noOfChars; i++) {
  1636.      if (visible[i]) 
  1637.         drawNervousChar(g, i);
  1638.       }
  1639.    }
  1640.    
  1641.    /**
  1642.     * Draw nervous character
  1643.     */
  1644.    void drawNervousChar(Graphics g, int index) 
  1645.    {
  1646.       int x = (int)(Math.random() * 2) + xPos[index];
  1647.       int y = (int)(Math.random() * 4) + yPos[index];
  1648.       drawChar(g, index, x+xStart, y+yStart);
  1649.    }
  1650.  
  1651.    /**
  1652.     * Draw normal character
  1653.     */
  1654.    void drawNormalChar(Graphics g, int index) 
  1655.    {
  1656.       drawChar(g, index, xPos[index]+xStart, yPos[index]+yStart);
  1657.    }
  1658.  
  1659.    /**
  1660.     * Draw character
  1661.     */
  1662.    void drawChar(Graphics g, int index, int x, int y)
  1663.    {
  1664.       int drawStyle = attr.drawStyle();
  1665.       if (drawStyle == attr.NONE || drawStyle == attr.SHADOW) {
  1666.      if (drawStyle == attr.SHADOW) {
  1667.         int shadowOffset = 4;
  1668.         if (brightFg == null) 
  1669.            brightFg = FunScrollColorSupport.brighter(fg, 0.75);
  1670.         g.setColor(brightFg);
  1671.         g.drawChars(chars, index, 1,
  1672.             x + shadowOffset, y + shadowOffset);
  1673.         g.setColor(fg);
  1674.      }
  1675.      
  1676.      // default draw style
  1677.      g.drawChars(chars, index, 1, x, y);
  1678.      return;
  1679.       }
  1680.  
  1681.       // draw style is ENGRAVE or EMBOSS
  1682.       
  1683.       // init colors (first time)
  1684.       if (darkBg == null) {
  1685.      darkBg = FunScrollColorSupport.darker(bg, 0.5);
  1686.      lightDarkBg = FunScrollColorSupport.darker(bg, 0.5 - (0.5/2));
  1687.      brightBg = FunScrollColorSupport.brighter(bg, 0.5);
  1688.       }
  1689.       
  1690.       int depth = 1;        // hardkoded ;-(
  1691.       Color upperLeftColor =
  1692.      (drawStyle == attr.ENGRAVE) ? darkBg : brightBg;
  1693.       Color upperRightColor =
  1694.      (drawStyle == attr.ENGRAVE) ? brightBg : darkBg;
  1695.       Color mainColor =
  1696.      (drawStyle == attr.ENGRAVE) ? lightDarkBg : bg;
  1697.       
  1698.       // upper left edge
  1699.       g.setColor(upperLeftColor);
  1700.       g.drawChars(chars, index, 1, x, y-depth);
  1701.       
  1702.       // lower right edge
  1703.       g.setColor(upperRightColor);
  1704.       g.drawChars(chars, index, 1, x+depth*2, y+depth);
  1705.       
  1706.       // main body of the character
  1707.       g.setColor(mainColor);
  1708.       g.drawChars(chars, index, 1, x+depth, y);
  1709.    }
  1710.    
  1711. }
  1712.  
  1713.  
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720.  
  1721. /*
  1722.  * Copyright (c) 1995 by Jan Andersson, Torpa Konsult AB.
  1723.  *
  1724.  * Permission to use, copy, and distribute this software for
  1725.  * NON-COMMERCIAL purposes and without fee is hereby granted
  1726.  * provided that this copyright notice appears in all copies.
  1727.  */
  1728.  
  1729. /**
  1730.  * FunScroll Color Support
  1731.  *
  1732.  * @version 1.1 96/06/23
  1733.  * @author  Jan Andersson (janne@torpa.se)
  1734.  */
  1735. class FunScrollColorSupport {
  1736.    static Hashtable colors;
  1737.  
  1738.    /**
  1739.     * Returns a darker version of color.
  1740.     */
  1741.    static Color darker(int r, int g, int b, double factor) {
  1742.       return new Color(Math.max((int)(r * (1 - factor)), 0),
  1743.                Math.max((int)(g * (1 - factor)), 0),
  1744.                Math.max((int)(b * (1 - factor)), 0));
  1745.    }
  1746.  
  1747.    /**
  1748.     * Returns a darker version of color.
  1749.     */
  1750.    static Color darker(Color c, double factor) {
  1751.       int r, g, b;
  1752.       r = c.getRed();
  1753.       g = c.getGreen();
  1754.       b = c.getBlue();
  1755.       return darker(r, g, b, factor);
  1756.    }
  1757.  
  1758.    /**
  1759.     * Returns a brighter version of color.
  1760.     */
  1761.    static Color brighter(int r, int g, int b, double factor) {
  1762.       int r2, g2, b2;
  1763.       r2 = r + (int)((255 - r) * factor);
  1764.       g2 = g + (int)((255 - g) * factor);
  1765.       b2 = b + (int)((255 - b) * factor);
  1766.       return new Color(r2, g2, b2);
  1767.    }
  1768.    
  1769.    /**
  1770.     * Returns a brighter version of color.
  1771.     */
  1772.    static Color brighter(Color c, double factor) {
  1773.       int r, g, b;
  1774.       r = c.getRed();
  1775.       g = c.getGreen();
  1776.       b = c.getBlue();
  1777.       return brighter(r, g, b, factor);
  1778.    }
  1779.  
  1780.    /**
  1781.     * lookup rgb string representing color name
  1782.     */
  1783.    public static String lookup(String name) {
  1784.       if(colors == null)
  1785.      createHashTable();
  1786.       String nameLowerCase = name.toLowerCase();
  1787.       return (String)colors.get(nameLowerCase);
  1788.    }
  1789.  
  1790.    /**
  1791.     * Create hash table
  1792.     */
  1793.    public static void createHashTable() {
  1794.       colors = new Hashtable(650);
  1795.       colors.put("aliceblue",         "f0f8ff");
  1796.       colors.put("antiquewhite",      "faebd7");
  1797.       colors.put("aquamarine",        "7fffd4");
  1798.       colors.put("azure",             "f0ffff");
  1799.       colors.put("beige",             "f5f5dc");
  1800.       colors.put("bisque",            "ffe4c4");
  1801.       colors.put("black",             "000000");
  1802.       colors.put("blanchedalmond",    "ffebcd");
  1803.       colors.put("blue",              "0000ff");
  1804.       colors.put("blueviolet",        "8a2be2");
  1805.       colors.put("brown",             "a52a2a");
  1806.       colors.put("burlywood",         "deb887");
  1807.       colors.put("cadetblue",         "5f9ea0");
  1808.       colors.put("chartreuse",        "7fff00");
  1809.       colors.put("chocolate",         "d2691e");
  1810.       colors.put("coral",             "ff7f50");
  1811.       colors.put("cornflowerblue",    "6495ed");
  1812.       colors.put("cornsilk",          "fff8dc");
  1813.       colors.put("cyan",              "00ffff");
  1814.       colors.put("darkgoldenrod",     "b8860b");
  1815.       colors.put("darkgreen",         "006400");
  1816.       colors.put("darkkhaki",         "bdb76b");
  1817.       colors.put("darkolivegreen",    "556b2f");
  1818.       colors.put("darkorange",        "ff8c00");
  1819.       colors.put("darkorchid",        "9932cc");
  1820.       colors.put("darksalmon",        "e9967a");
  1821.       colors.put("darkseagreen",      "8fbc8f");
  1822.       colors.put("darkslateblue",     "483d8b");
  1823.       colors.put("darkslategray",     "2f4f4f");
  1824.       colors.put("darkslategrey",     "2f4f4f");
  1825.       colors.put("darkturquoise",     "00ced1");
  1826.       colors.put("darkviolet",        "9400d3");
  1827.       colors.put("deeppink",          "ff1493");
  1828.       colors.put("deepskyblue",       "00bfff");
  1829.       colors.put("dimgray",           "696969");
  1830.       colors.put("dimgrey",           "696969");
  1831.       colors.put("dodgerblue",        "1e90ff");
  1832.       colors.put("firebrick",         "b22222");
  1833.       colors.put("floralwhite",       "fffaf0");
  1834.       colors.put("forestgreen",       "228b22");
  1835.       colors.put("green",             "00ff00");
  1836.       colors.put("gainsboro",         "dcdcdc");
  1837.       colors.put("ghostwhite",        "f8f8ff");
  1838.       colors.put("gold",              "ffd700");
  1839.       colors.put("goldenrod",         "daa520");
  1840.       colors.put("gray",              "bebebe");
  1841.       colors.put("honeydew",          "f0fff0");
  1842.       colors.put("hotpink",           "ff69b4");
  1843.       colors.put("indianred",         "cd5c5c");
  1844.       colors.put("ivory",             "fffff0");
  1845.       colors.put("khaki",             "f0e68c");
  1846.       colors.put("lavender",          "e6e6fa");
  1847.       colors.put("lavenderblush",     "fff0f5");
  1848.       colors.put("lawngreen",         "7cfc00");
  1849.       colors.put("lemonchiffon",      "fffacd");
  1850.       colors.put("lightblue",         "add8e6");
  1851.       colors.put("lightcoral",        "f08080");
  1852.       colors.put("lightcyan",         "e0ffff");
  1853.       colors.put("lightgoldenrod",    "eedd82");
  1854.       colors.put("lightgoldenrodyellow","fafad2");
  1855.       colors.put("lightgray",         "d3d3d3");
  1856.       colors.put("lightgrey",         "d3d3d3");
  1857.       colors.put("lightpink",         "ffb6c1");
  1858.       colors.put("lightsalmon",       "ffa07a");
  1859.       colors.put("lightseagreen",     "20b2aa");
  1860.       colors.put("lightskyblue",      "87cefa");
  1861.       colors.put("lightslateblue",    "8470ff");
  1862.       colors.put("lightslategray",    "778899");
  1863.       colors.put("lightslategrey",    "778899");
  1864.       colors.put("lightsteelblue",    "b0c4de");
  1865.       colors.put("lightyellow",       "ffffe0");
  1866.       colors.put("limegreen",         "32cd32");
  1867.       colors.put("linen",             "faf0e6");
  1868.       colors.put("magenta",           "ff00ff");
  1869.       colors.put("maroon",            "b03060");
  1870.       colors.put("mediumaquamarine",  "66cdaa");
  1871.       colors.put("mediumblue",        "0000cd");
  1872.       colors.put("mediumorchid",      "ba55d3");
  1873.       colors.put("mediumpurple",      "9370db");
  1874.       colors.put("mediumseagreen",    "3cb371");
  1875.       colors.put("mediumslateblue",   "7b68ee");
  1876.       colors.put("mediumspringgreen", "00fa9a");
  1877.       colors.put("mediumturquoise",   "48d1cc");
  1878.       colors.put("mediumvioletred",   "c71585");
  1879.       colors.put("midnightblue",      "191970");
  1880.       colors.put("mintcream",         "f5fffa");
  1881.       colors.put("mistyrose",         "ffe4e1");
  1882.       colors.put("moccasin",          "ffe4b5");
  1883.       colors.put("navajowhite",       "ffdead");
  1884.       colors.put("navy",              "000080");
  1885.       colors.put("navyblue",          "000080");
  1886.       colors.put("oldlace",           "fdf5e6");
  1887.       colors.put("olivedrab",         "6b8e23");
  1888.       colors.put("orange",            "ffa500");
  1889.       colors.put("orangered",         "ff4500");
  1890.       colors.put("orchid",            "da70d6");
  1891.       colors.put("palegoldenrod",     "eee8aa");
  1892.       colors.put("palegreen",         "98fb98");
  1893.       colors.put("paleturquoise",     "afeeee");
  1894.       colors.put("palevioletred",     "db7093");
  1895.       colors.put("papayawhip",        "ffefd5");
  1896.       colors.put("peachpuff",         "ffdab9");
  1897.       colors.put("peru",              "cd853f");
  1898.       colors.put("pink",              "ffc0cb");
  1899.       colors.put("plum",              "dda0dd");
  1900.       colors.put("powderblue",        "b0e0e6");
  1901.       colors.put("purple",            "a020f0");
  1902.       colors.put("red",               "ff0000");
  1903.       colors.put("rosybrown",         "bc8f8f");
  1904.       colors.put("royalblue",         "4169e1");
  1905.       colors.put("saddlebrown",       "8b4513");
  1906.       colors.put("salmon",            "fa8072");
  1907.       colors.put("sandybrown",        "f4a460");
  1908.       colors.put("seagreen",          "2e8b57");
  1909.       colors.put("seashell",          "fff5ee");
  1910.       colors.put("sienna",            "a0522d");
  1911.       colors.put("skyblue",           "87ceeb");
  1912.       colors.put("slateblue",         "6a5acd");
  1913.       colors.put("slategray",         "708090");
  1914.       colors.put("slategrey",         "708090");
  1915.       colors.put("snow",              "fffafa");
  1916.       colors.put("springgreen",       "00ff7f");
  1917.       colors.put("steelblue",         "4682b4");
  1918.       colors.put("tan",               "d2b48c");
  1919.       colors.put("thistle",           "d8bfd8");
  1920.       colors.put("tomato",            "ff6347");
  1921.       colors.put("turquoise",         "40e0d0");
  1922.       colors.put("violet",            "ee82ee");
  1923.       colors.put("violetred",         "d02090");
  1924.       colors.put("wheat",             "f5deb3");
  1925.       colors.put("white",             "ffffff");
  1926.       colors.put("whitesmoke",        "f5f5f5");
  1927.       colors.put("yellow",            "ffff00");
  1928.       colors.put("yellowgreen",       "9acd32");
  1929.    }
  1930. }
  1931.  
  1932.  
  1933.  
  1934.  
  1935.  
  1936.  
  1937.  
  1938.  
  1939.  
  1940.  
  1941. /*
  1942.  * Copyright (c) 1995 by Jan Andersson, Torpa Konsult AB.
  1943.  *
  1944.  * Permission to use, copy, and distribute this software for
  1945.  * NON-COMMERCIAL purposes and without fee is hereby granted
  1946.  * provided that this copyright notice appears in all copies.
  1947.  */
  1948. /**
  1949.  * Attributes of FunScroll Animated Text
  1950.  *
  1951.  * @version 1.3 96/08/20
  1952.  * @author  Jan Andersson (janne@torpa.se)
  1953.  */
  1954. class FunScrollTextAttr
  1955. {
  1956.                 // scroll styles:
  1957.    static final int NONE = 0;    // no scrolling (default)
  1958.    static final int LEFT = 1;    // scroll left
  1959.    static final int RIGHT = 2;    // ... right
  1960.    static final int UP = 3;    // ... up
  1961.    static final int DOWN = 4;    // ... down
  1962.    static final int EXPLODE = 5;// explode (only for endScroll)
  1963.                 // text styles:
  1964.    static final int NORMAL = 0;    // normal (default)
  1965.    static final int NERVOUS = 1; // "nervous" text
  1966.    static final int SINEWAVE = 2; // sine-wave text
  1967.                  // text draw styles:
  1968.    static final int EMBOSS = 1;     
  1969.    static final int ENGRAVE = 2;
  1970.    static final int SHADOW = 3;
  1971.                 // text line alignment
  1972.    static final int CENTER = 0;
  1973.    
  1974.    String msg = "";        // message line
  1975.    String delimiters = "<>";    // used delimiters (default is "<>")
  1976.    int startScroll = NONE;    // start scroll style
  1977.    int endScroll = NONE;    // end scroll style
  1978.    int showDelay = 0;        // show delay
  1979.    int endDelay = -1;        // end delay
  1980.    int style = NORMAL;        // text style
  1981.    int drawStyle = NONE;    // text draw style
  1982.    int align = CENTER;        // text line alignment
  1983.    String color = null;        // text color
  1984.    
  1985.    public FunScrollTextAttr(String line, String delim)
  1986.    {
  1987.       if (delim != null) {
  1988.      // used specified delimiter
  1989.      delimiters = delim;
  1990.       }
  1991.       parse(line);
  1992.    }
  1993.  
  1994.    public String msg()
  1995.    {
  1996.       return msg;
  1997.    }
  1998.    
  1999.    public int startScroll()
  2000.    {
  2001.       return startScroll;
  2002.    }
  2003.    
  2004.    public int endScroll()
  2005.    {
  2006.       return endScroll;
  2007.    }
  2008.    
  2009.    public int showDelay()
  2010.    {
  2011.       return showDelay;
  2012.    }
  2013.    
  2014.    public int endDelay()
  2015.    {
  2016.       return endDelay;
  2017.    }
  2018.  
  2019.    public int style()
  2020.    {
  2021.       return style;
  2022.    }
  2023.  
  2024.    public int align()
  2025.    {
  2026.       return align;
  2027.    }
  2028.    
  2029.    public int drawStyle()
  2030.    {
  2031.       return drawStyle;
  2032.    }
  2033.  
  2034.    public String color()
  2035.    {
  2036.       return color;
  2037.    }
  2038.    
  2039.    void parse(String line)
  2040.    {
  2041.       StringTokenizer st = new StringTokenizer(line, delimiters);
  2042.       boolean gotText = false;
  2043.       while (st.hasMoreTokens()) {
  2044.      int scroll = -1;
  2045.      String token = st.nextToken();
  2046.  
  2047.      // get scroll style
  2048.      if (token.equalsIgnoreCase("left")) 
  2049.         scroll = LEFT;
  2050.      else if (token.equalsIgnoreCase("right")) 
  2051.         scroll = RIGHT;
  2052.      else if (token.equalsIgnoreCase("up")) 
  2053.         scroll = UP;
  2054.      else if (token.equalsIgnoreCase("down")) 
  2055.         scroll = DOWN;
  2056.      else if (gotText && token.equalsIgnoreCase("explode")) 
  2057.         scroll = EXPLODE;
  2058.      if (scroll >= 0) {
  2059.         if (!gotText)
  2060.            startScroll = scroll;
  2061.         else
  2062.            endScroll = scroll;
  2063.         continue;
  2064.      }
  2065.  
  2066.      // get text style
  2067.      if (token.equalsIgnoreCase("nervous")) {
  2068.         style = NERVOUS;
  2069.         continue;
  2070.      }
  2071.      if (token.equalsIgnoreCase("sine-wave")) {
  2072.         style = SINEWAVE;
  2073.         continue;
  2074.      }
  2075.      
  2076.      // get text draw style
  2077.      if (token.equalsIgnoreCase("emboss")) {
  2078.         drawStyle = EMBOSS;
  2079.         continue;
  2080.      }
  2081.      if (token.equalsIgnoreCase("engrave")) {
  2082.         drawStyle = ENGRAVE;
  2083.         continue;
  2084.      }
  2085.      if (token.equalsIgnoreCase("shadow")) {
  2086.         drawStyle = SHADOW;
  2087.         continue;
  2088.      }
  2089.  
  2090.      // get color
  2091.      if (token.length() > 6 &&
  2092.          token.substring(0,6).equalsIgnoreCase("color=")) {
  2093.         color = token.substring(6);
  2094.         continue;
  2095.      }
  2096.  
  2097.      // get color
  2098.      if (token.length() > 6 &&
  2099.          token.substring(0,6).equalsIgnoreCase("align=")) {
  2100.         String alignStr = token.substring(6);
  2101.         if (alignStr.equalsIgnoreCase("left"))
  2102.            align = LEFT;
  2103.         else if (alignStr.equalsIgnoreCase("right"))
  2104.            align = RIGHT;
  2105.         else
  2106.            align = CENTER;
  2107.         continue;
  2108.      }
  2109.  
  2110.      // check if integer, if so assume delay value
  2111.      boolean isInt = true;
  2112.      for (int i=0; i<token.length(); i++) {
  2113.         int digit = Character.digit(token.charAt(i), 10);
  2114.         if (digit < 0) {
  2115.            // not a digit
  2116.            isInt = false;
  2117.            break;
  2118.         }
  2119.      }
  2120.      if (isInt) {
  2121.         try {
  2122.            if (!gotText)
  2123.           showDelay = Integer.parseInt(token);
  2124.            else
  2125.           endDelay = Integer.parseInt(token);
  2126.         } catch (NumberFormatException ne) {}
  2127.         continue;
  2128.      }
  2129.      else {
  2130.         // assume text string parsed
  2131.         if (!gotText) {
  2132.            msg = token;
  2133.            gotText = true;
  2134.         }
  2135.      }
  2136.       }
  2137.    }
  2138.  
  2139. }
  2140.  
  2141. FunScroll.java
  2142.