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