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