home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Online 1997 October
/
PCO1097.ISO
/
FilesBBS
/
FREI
/
FSCROLL.EXE
/
SRC
/
FunScroll.java
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Java Source
|
1997-09-02
|
37.9 KB
|
1,339 lines
/*
* Copyright (c) 1996 by Jan Andersson, Torpa Konsult AB.
*
* Permission to use, copy, and distribute this software for
* NON-COMMERCIAL purposes and without fee is hereby granted
* provided that this copyright notice appears in all copies.
*/
import java.applet.*;
import java.awt.*;
import java.awt.image.*;
import java.util.*;
import java.io.*;
import java.net.*;
/**
* FunScroll - A Funnier (?) scrolling text/image applet.
*
* @version 1.35 97/09/01
* @author Jan Andersson (janne@torpa.se)
*
*/
public class FunScroll extends Applet implements Runnable
{
static final int MaxLines = 50; // max no. of line parameters
static final int ShadowIn = 0; // frame types:
static final int ShadowOut = 1;
static final int ShadowEtchedIn = 2;
static final int ShadowEtchedOut = 3;
Image bgImage = null; // backgound image
Image tiledBgImage = null; // tiled backgound image
MediaTracker mediaTracker; // to track loading of backgound image
Thread thread = null; // animation thread
ThreadGroup threadGroup = null; // animation thread group
boolean suspended = false; // animation thread suspended
int threadDelay = 100; // animation thread delay
String lineData = null; // line data file (url)
boolean usingCgi = false; // if line data file is CGI
boolean randomize = false; // true will randomly select line to display
boolean showAbout = true; // show "about" popup on shift-click
int updateInterval = 0; // update interval (to read data file)
int animateCount = 0; // reload data (from data file)
Font font = null; // default font
int dx = 3; // delta x
int dy = 2; // delta y
String delim = null; // text attribute delimiters
long threadStartTime; // time thread started
Vector animatedObjects = null; // animated objects
Vector urlStrings = null; // associated url's
String urlTarget = null; // target widow or frame
int noOfObjects = 0; // number of objects
int currentObjectIndex = 0; // current object index
FunScrollAnimate currentObj; // current object instance
int frameWidth = 0; // frame width
int frameType = ShadowIn; // frame type
int frameMargin = 0; // frame margin
Color frameDark1 = null; // darker frame color
Color frameDark2 = null; // (slightly) darker frame color
Color frameBright = null; // brighter frame color
Image offImage; // "off-screen" image
Dimension offSize; // "off-screen" size
Dimension animAreaSize; // anim. area size
Hashtable urlParameters = null; // parameters scanned from data file
protected boolean initiated = false; // true when initiated
static final boolean debug = false;// debug flag
static final String sourceLocation =
"http://www.algonet.se/~jannea/FunScroll/FunScroll.html";
static final String versionInfo =
"FunScroll 3.2";
/**
* Init applet
*/
public void init()
{
// we need a few parameters to draw the initial message...
// get color parameters
Color fg = readColor(getParameter("fgColor"), Color.black);
Color bg = readColor(getParameter("bgColor"), getBackground());
setBackground(bg);
setForeground(fg);
// get current Thread group
threadGroup = Thread.currentThread().getThreadGroup();
}
/**
* Init parameters and create animated text instances
*/
public void initParameters()
{
Vector lineVector = new Vector();
urlStrings = new Vector();
// cgi/lineData parameter
String par = getParameter("cgi");
if (par != null) {
usingCgi = true;
}
else {
par = getParameter("lineData");
}
if (par != null) {
lineData = par;
initLineParametersFromInputURL(lineData, lineVector, urlStrings);
par = getParameter("updateInterval");
if (par != null)
updateInterval = Integer.valueOf(par).intValue();
}
else
initLineParameters(lineVector, urlStrings);
// get color parameters
Color fg = readColor(getParameter("fgColor"), Color.black);
Color bg = readColor(getParameter("bgColor"), getBackground());
setBackground(bg);
setForeground(fg);
// init frame (border) params
frameWidth = getParameterToInt("frameWidth", frameWidth);
frameMargin = getParameterToInt("frameMargin", frameMargin);
frameType = getParameterToFrameType("frameType", frameType);
// get frame/window target
urlTarget = getParameter("target");
// get background image
par = getParameter("bgImage");
if (par != null) {
bgImage = getImage(getCodeBase(), par);
mediaTracker = new MediaTracker(this);
mediaTracker.addImage(bgImage, 0);
}
// get font parameters
font = getParameterToFont("font", "style", "size");
// get delay value
threadDelay = getParameterToInt("delay", threadDelay);
// get dx/dy movement
dx = getParameterToInt("dx", dx);
dy = getParameterToInt("dy", dy);
// get delimiters string
delim = getParameter("delim");
// randomize?
par = getParameter("randomize");
if (par != null && par.equalsIgnoreCase("True"))
randomize = true;
// show about?
par = getParameter("showAbout");
if (par != null && par.equalsIgnoreCase("False"))
showAbout = false;
// create animated texts
createAnimates(lineVector,
font, getForeground(), getBackground(),
dx, dy, delim);
initiated = true;
}
/**
* Gets a parameter of the applet.
*
* Use this function to overload java.applet.Applet.getParameter
* to handle ISO Latin 1 characters correctly in Netscape 2.0.
* Following a suggestion from Peter Sylvester,
* Peter.Sylvester@edelweb.fr.
*
* Note: this is a work-a-round for a bug in Netscape and should
* be removed!
*/
public String getParameter(String s) {
// 1'st - get parameter from applet (HTML)
String par = super.getParameter(s);
// next - get parameter from input URL
if (urlParameters != null) {
String par2 = (String)urlParameters.get(s.toLowerCase());
if (par2 != null)
par = par2;
}
if (par == null)
return null;
// hack to handle ISO Latin 1 characters correctly in Netscape 2.0.
// work-a-round for a bug in Netscap 2.0!
char ec[] = par.toCharArray();
for (int i=0; i < ec.length; i++) {
if (ec[i] >= 0xff00)
ec[i] &= 0x00ff ;
}
return(new String(ec)) ;
}
/**
* Parameter support functions:
*/
public int getParameterToInt(String par, int defaultval) {
String s = getParameter(par);
if(s == null)
return defaultval;
else
return(Integer.parseInt(s));
}
public int getParameterToFrameType(String par, int defaultval) {
String s = getParameter(par);
if(s == null)
return defaultval;
if (s.equalsIgnoreCase("ShadowOut"))
return ShadowOut;
else if (s.equalsIgnoreCase("ShadowEtchedIn"))
return ShadowEtchedIn;
else if (s.equalsIgnoreCase("ShadowEtchedOut"))
return ShadowEtchedOut;
else
return ShadowIn;
}
public Font getParameterToFont(String namePar, String stylePar,
String sizePar)
{
String fontName = getParameter(namePar);
if (fontName == null)
fontName = "TimesRoman";
String fontStyle = getParameter(stylePar);
int style = Font.BOLD;
if (fontStyle != null) {
if (fontStyle.equalsIgnoreCase("plain"))
style = Font.PLAIN;
else if (fontStyle.equalsIgnoreCase("bold"))
style = Font.BOLD;
else if (fontStyle.equalsIgnoreCase("italic"))
style = Font.ITALIC;
else if (fontStyle.equalsIgnoreCase("bolditalic"))
style = Font.ITALIC|Font.BOLD;
}
int size = getParameterToInt(sizePar, 24);
// make sure fonts are created with the right size
// Note: size-parameter are plattform dependent and the
// only way to get the same size on all plattforms is to
// check the "real" size using FontMetrics.
// Note: we only loop until "real" size if less than 6
// or size differs more that 3 pixels...
FontMetrics fm;
int realSize = size;
dbg("init font...");
Font font = null;
do {
dbg("trying: " + fontName + "," + realSize);
font = new Font(fontName, style, realSize--);
fm = getFontMetrics(font);
} while ((fm.getDescent() + fm.getAscent()) > size &&
realSize >= size-3 && size >= 6);
if (realSize < size-3 || size < 6)
// assume weird font used... Use parsed size.
font = new Font(fontName, style, size);
dbg("using font: " + font.toString());
return font;
}
/**
* Init unparsed line parameters (Vector of Strings) and
* (possibly) associated url's.
*/
protected void initLineParameters(Vector lineVector, Vector urlVector)
{
// get unparsed line parameters
dbg("get line parameters...");
for (int i=0; i<MaxLines; i++) {
String lineParName = "line" + i;
String linePar = getParameter(lineParName);
String urlParName = "url" + i;
String urlPar = getParameter(urlParName);
if (linePar != null) {
dbg(" " + lineParName + ":" + linePar);
lineVector.addElement(linePar);
dbg(" " + urlParName + ":" + urlPar);
urlVector.addElement(urlPar);
}
}
if (lineVector.size() <= 0)
// assume no line parameter provided; use default
initDefaultLineParameters(lineVector);
}
/**
* The current character. Ugly :-(
*/
private int c;
/**
* Scan spaces.
*/
private void skipSpace(InputStream in) throws IOException
{
while((c >= 0) &&
((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'))) {
c = in.read();
}
}
/**
* Skip comment line
*/
private void skipCommentLine(InputStream in) throws IOException
{
dbg("skipCommentLine()");
while((c >= 0) && (c != '\n') && (c != '\r')) {
c = in.read();
}
}
/**
* Scan identifier
*/
private String scanIdentifier(InputStream in) throws IOException
{
StringBuffer buf = new StringBuffer();
while (true) {
if (((c >= 'a') && (c <= 'z')) ||
((c >= 'A') && (c <= 'Z')) ||
((c >= '0') && (c <= '9')) || (c == '_')) {
buf.append((char)c);
c = in.read();
} else {
return buf.toString();
}
}
}
/**
* Scan tag
*/
private Hashtable scanTag(InputStream in) throws IOException {
Hashtable atts = new Hashtable();
skipSpace(in);
while (c >= 0 && c != '>') {
String att = scanIdentifier(in);
String val = "";
skipSpace(in);
if (c == '=') {
int quote = -1;
c = in.read();
skipSpace(in);
if ((c == '\'') || (c == '\"')) {
quote = c;
c = in.read();
}
StringBuffer buf = new StringBuffer();
while ((c > 0) &&
(((quote < 0) && (c != ' ') && (c != '\t')
&&
(c != '\n') && (c != '\r') && (c != '>'))
|| ((quote >= 0) && (c != quote)))) {
buf.append((char)c);
c = in.read();
}
if (c == quote) {
c = in.read();
}
skipSpace(in);
val = buf.toString();
}
atts.put(att.toLowerCase(), val);
skipSpace(in);
}
return atts;
}
/**
* Scan input data stream
*/
private void parseInput(DataInputStream in, Vector lineVector,
Vector urlVector)
throws IOException
{
c = in.read();
while (c >= 0) {
if (c == '#')
skipCommentLine(in);
else if (c == '<') {
// probably applet parameter!
c = in.read();
String nm = scanIdentifier(in);
if (nm.equalsIgnoreCase("param")) {
// yes; we have a <param tag
Hashtable t = scanTag(in);
String att = (String)t.get("name");
if (att == null) {
System.out.println(
"Warning: <param name=... value=...>" +
"tag requires name attribute.");
}
else {
String val = (String)t.get("value");
if (val == null) {
System.out.println(
"Warning: <param name=... value=...>" +
"tag requires value attribute.");
}
else {
if (urlParameters == null)
urlParameters = new Hashtable();
dbg("parseInput() put " + att + " = '" + val + "'");
urlParameters.put(att.toLowerCase(), val);
}
}
}
else {
// assume line data; read the rest as such!
readLineData(in, "<" + nm + ">", lineVector, urlVector);
in.close();
return;
}
}
else {
// assume line data; read the rest as such!
readLineData(in, "", lineVector, urlVector);
in.close();
return;
}
if (c == '>')
c = in.read();
skipSpace(in);
}
in.close();
}
String readDataLine(DataInputStream is)
throws IOException
{
String line = is.readLine();
while (line != null &&
(line.length() == 0 || line.charAt(0) == '#'))
line = is.readLine();
return line;
}
void readLineData(DataInputStream is, String add,
Vector lineVector, Vector urlVector)
throws IOException
{
String line = null;
line = add + is.readLine();
while (line != null) {
dbg("readLineData: " + line);
// add to line vector
lineVector.addElement(line);
line = readDataLine(is);
if (line != null && line.length() > 4 &&
line.substring(0, 4).equalsIgnoreCase("URL:")) {
// assume url specified; add to URL vector
urlVector.addElement(line.substring(4));
line = readDataLine(is);
}
else {
urlVector.addElement(null);
}
}
}
/**
* Init unparsed line parameters (Vector of Strings) and
* (possibly) associated url's from input file.
*/
protected void initLineParametersFromInputURL(
String urlString, Vector lineVector, Vector urlVector) {
if (usingCgi) {
// post as CGI
postCGI(urlString, lineVector, urlVector);
return;
}
// create URL
URL url = null;
DataInputStream is = null;
// 1'st, try URL directly
try {
url = new URL(urlString);
dbg("initLineParametersFromInputURL(): using direct URL: " + url);
// make sure data isn't cashed
URLConnection urlc = url.openConnection();
urlc.setUseCaches(false);
// open input stream
is = new DataInputStream(urlc.getInputStream());
} catch (Exception e) {
dbg("initLineParametersFromInputURL(): Can't read URL:" + url);
is = null;
}
if (is == null) {
// try URL in context of document
try {
url = new URL(getDocumentBase(), urlString);
dbg("initLineParametersFromInputURL(): using rel. URL:" + url);
// make sure data isn't cashed
URLConnection urlc = url.openConnection();
urlc.setUseCaches(false);
// open input stream
is = new DataInputStream(urlc.getInputStream());
} catch (Exception e) {
dbg("initLineParametersFromInputURL(): Can't read URL:" + url);
is = null;
initURLErrorLineParameters(urlString, lineVector);
updateInterval = 0;
return;
}
}
// parse
try {
parseInput(is, lineVector, urlVector);
}
catch (IOException e) {
// ignore (?)
}
if (lineVector.size() <= 0) {
// assume no line parameter provided; use error message
dbg("initLineParametersFromInputURL(): No lines!");
initURLErrorLineParameters(urlString, lineVector);
updateInterval = 0;
}
}
public void postCGI(String script, Vector lineVector, Vector urlVector)
{
String home = getCodeBase().getHost();
int port = getCodeBase().getPort();
if (port == -1)
port = 80;
dbg("postCGI; home: " + home + "port: " + port);
//create a client socket
Socket sock;
try {
sock = new Socket(home, port);
}
catch (Exception e) {
dbg("postCGI(): Can't create socket:" + e);
initURLErrorLineParameters(script, lineVector);
updateInterval = 0;
return;
}
OutputStream outp;
InputStream inp;
DataOutputStream dataout;
DataInputStream datain;
// Obtain output stream to communicate with the server
try {
outp = sock.getOutputStream();
inp = sock.getInputStream();
}
catch (Exception e) {
try {
sock.close();
}
catch (IOException ee) {}
dbg("postCGI(): Can't create output stream:" + e);
initURLErrorLineParameters(script, lineVector);
updateInterval = 0;
return;
}
try {
dataout = new DataOutputStream(outp);
datain = new DataInputStream(inp);
}
catch (Exception e) {
try {
sock.close();
}
catch (IOException ee) {;}
dbg("postCGI(): Can't create output stream:" + e);
initURLErrorLineParameters(script, lineVector);
updateInterval = 0;
return;
}
// Send http request to server and get return data
try {
// HTTP header
String ctype = "application/octet-stream";
dataout.writeBytes("POST " + script + " HTTP/1.0\r\n");
dataout.writeBytes("Content-type: " + ctype + "\r\n");
dataout.writeBytes("Content-length: 0\r\n");
dataout.writeBytes("User-Agent: " + versionInfo + "\r\n");
dataout.writeBytes("\r\n"); // end of header
// read response headers
String line;
while ((line = datain.readLine()) != null && !line.equals("")) {
dbg("postCGI(); respose header: " + line);
}
// read and parse response data
parseInput(datain, lineVector, urlVector);
}
catch (Exception e) {
dbg("postCGI(): IOException when reading stream!");
}
if (lineVector.size() <= 0) {
// assume no line parameter provided; use error message
dbg("postCGI(): No lines!");
initURLErrorLineParameters(script, lineVector);
updateInterval = 0;
}
// close up shop
try {
dataout.close();
datain.close();
}
catch (IOException e) {;}
try {
sock.close();
}
catch (IOException e) {;}
}
/**
* Init default line parameters (Vector of Strings).
* Used when not line parameters specified.
*/
protected void initDefaultLineParameters(Vector v) {
threadDelay = 200;
v.addElement("<25><typed>" + getAppletInfo());
v.addElement("<100>No parameters specified!");
}
/**
* Init error line parameters (Vector of Strings).
* Used at error, when trying to get input from URL.
*/
protected void initURLErrorLineParameters(String url, Vector v) {
threadDelay = 200;
v.addElement("<nervous><30><color=#FF0000>Error!");
v.addElement("<100>Could not read url: " + url);
}
/**
* Applet Info.
*/
public String getAppletInfo() {
return versionInfo;
}
/**
* Parameter Info.
*/
public String[][] getParameterInfo() {
// More should be added...
String[][] info = {
{"line<n>", "string", "Message line <n>" },
{"url<n>", "string", "URL <n>" },
{"showAbout","boolean", "Display about popup on shift-click" },
{"randomize","boolean", "Display message lines in random order" },
{"target","string", "Default frame or window target" },
{"lineData","string", "Message line data file" },
{"cgi","string", "CGI script to be used to read message lines" },
{"updateInterval", "int", "Update interval to read data file (0)" },
{"delim", "string", "Delimiter string (<>)" },
{"frameWidth", "int", "Frame border width (0)" },
{"frameMargin", "int", "Frame margin width (0)" },
{"frameType", "string", "Frame type (ShadowIn)" },
{"font", "string", "Message font (TimesRoman)" },
{"style", "string", "Message font style (bold)" },
{"size", "int", "Message font size (22)" },
{"delay", "int", "Animation delay time in millisec. (100)" },
{"dx", "int",
"No of pixels to move horizontally for each animation (2)" },
{"dy", "int",
"No of pixels to move vertically for each animation (1)" },
{"fgColor", "string", "Foreground Color" },
{"bgColor", "string", "Background Color" },
};
return info;
}
/**
* Convert a Hexadecimal String with RGB-Values to Color
* Uses aDefault, if no or not enough RGB-Values
*/
public Color readColor(String aColor, Color aDefault) {
if (aColor == null)
return aDefault;
Integer rgbValue = null;
try {
if (aColor.startsWith("#"))
rgbValue = Integer.valueOf(aColor.substring(1), 16);
else if (aColor.startsWith("0x"))
rgbValue = Integer.valueOf(aColor.substring(2), 16);
else
// assume symbolic color name
rgbValue = Integer.valueOf(FunScrollColorSupport.lookup(aColor), 16);
} catch (NumberFormatException e) {
rgbValue = null;
}
if (rgbValue == null)
return aDefault;
return new Color(rgbValue.intValue());
}
/**
* Create animated text vector. I.e vector with FunScrollAnimate
* instances.
*/
public void createAnimates(Vector lines, Font font,
Color fg, Color bg,
int dx, int dy,
String delim)
{
noOfObjects = 0;
animatedObjects = new Vector(lines.size());
dbg("Creating Animated Text...");
for (int i=0; i<lines.size(); i++) {
dbg(" " + (String) lines.elementAt(i));
animatedObjects.addElement(
new FunScrollAnimate(
this, (String) lines.elementAt(i), font,
fg, bg, dx, dy, delim));
noOfObjects++;
}
currentObjectIndex = 0;
if (randomize)
currentObjectIndex = (int)(noOfObjects * Math.random());
currentObj = (FunScrollAnimate)
animatedObjects.elementAt(currentObjectIndex);
// set offSize to zero to be sure that offImage is re-initiated
offSize = new Dimension(0,0);
}
/**
* Animate the texts
*/
public void animate(Graphics g) {
// update current text
if (currentObj.update(g)) {
// done; get next text
if (randomize)
currentObjectIndex = (int)(noOfObjects * Math.random());
else
currentObjectIndex++;
if (currentObjectIndex >= noOfObjects) {
// all text lines animated
if (lineData != null && updateInterval > 0)
animateCount++;
currentObjectIndex = 0;
}
currentObj = (FunScrollAnimate)
animatedObjects.elementAt(currentObjectIndex);
currentObj.reset();
}
}
/**
* Paint tiled background image.
* Based on code by Tony Kolman, 02/20/96.
*
* Note: there are performance problems here.
*/
public void paintTiledImage(Graphics g, Image im,
int offset, int width, int height) {
if (tiledBgImage == null) {
int imgw = im.getWidth(null);
int imgh = im.getHeight(null);
if (imgw > 0 && imgh > 0) {
// we have the background image; create tiled background image
tiledBgImage = createImage(width, height);
Graphics tiledBgGraphics = tiledBgImage.getGraphics();
tiledBgGraphics.setColor(getBackground());
tiledBgGraphics.fillRect(0, 0, width, height);
for (int x = 0; x < width; x += imgw) {
for (int y = 0; y < height; y += imgh) {
tiledBgGraphics.drawImage(im, x, y, null);
}
}
tiledBgGraphics.dispose();
}
}
if (tiledBgImage != null) {
g.drawImage(tiledBgImage, offset, offset, null);
}
}
/**
* Paint last animation
*/
public void paint(Graphics g) {
if (offImage != null)
// paint the image onto the screen
g.drawImage(offImage, 0, 0, null);
}
/**
* Init "loading..." message
*/
public void initLoadMessage()
{
dbg("initLoadMessage()");
if (offImage == null) {
// create the initial offscreen graphics context
offSize = size();
offImage = createImage(offSize.width, offSize.height);
}
Graphics offGraphics = offImage.getGraphics();
offGraphics.setColor(getBackground());
offGraphics.fillRect(0, 0, offSize.width, offSize.height);
offGraphics.setColor(getForeground());
offGraphics.drawString("FunScroll: Loading applet...",
10, offSize.height/2);
offGraphics.dispose();
dbg("initLoadMessage() done");
}
/**
* Draw a frame at the specified position.
*/
protected void drawFrame(Graphics g, int x, int y, int w, int h,
int type, int thickness, int margin)
{
if(thickness <= 0)
return;
if (frameDark1 == null) {
// create frame colors from background
frameDark1 = FunScrollColorSupport.darker(getBackground(), .50);
frameDark2 = FunScrollColorSupport.darker(getBackground(), .10);
frameBright = FunScrollColorSupport.brighter(getBackground(), .50);
}
switch (type) {
case ShadowOut:
for(int i=0;i<thickness;i++) {
// top left
g.setColor(frameBright);
drawTopLeftLines(g, x, y, w, h, i, margin);
// bottom right
g.setColor(frameDark1);
drawBottomRightLines(g, x, y, w, h, i, margin);
}
break;
case ShadowEtchedIn:
for(int i=0;i<thickness;i++) {
// top left
if(i == 0)
g.setColor(frameDark1);
else if (i == thickness-1)
g.setColor(frameBright);
else
g.setColor(frameDark2);
drawTopLeftLines(g, x, y, w, h, i, margin);
// bottom right
if(i == 0)
g.setColor(frameBright);
else if (i == thickness-1)
g.setColor(frameDark1);
else
g.setColor(frameDark2);
drawBottomRightLines(g, x, y, w, h, i, margin);
}
break;
case ShadowEtchedOut:
for(int i=0;i<thickness;i++) {
// top left
if(i == 0)
g.setColor(frameBright);
else if (i == thickness-1)
g.setColor(frameDark1);
else
g.setColor(getBackground());
drawTopLeftLines(g, x, y, w, h, i, margin);
// bottom right
if(i == 0)
g.setColor(frameDark1);
else if (i == thickness-1)
g.setColor(frameBright);
else
g.setColor(getBackground());
drawBottomRightLines(g, x, y, w, h, i, margin);
}
break;
default: // ShadowIn (default)
for(int i=0;i<thickness;i++) {
// top left
g.setColor(frameDark1);
drawTopLeftLines(g, x, y, w, h, i, margin);
// bottom right
g.setColor(frameBright);
drawBottomRightLines(g, x, y, w, h, i, margin);
}
}
// reset background color
g.setColor(getBackground());
}
void drawTopLeftLines(Graphics g,
int x, int y, int w, int h, int i, int margin)
{
g.drawLine(x+margin+i, y+margin+i, x+w-margin-i-1, y+margin+i);
g.drawLine(x+margin+i, y+margin+i, x+margin+i, y+h-margin-i-1);
}
void drawBottomRightLines(Graphics g,
int x, int y, int w, int h, int i, int margin)
{
g.drawLine(x+margin+i, y+h-margin-i-1, x+w-margin-i-1, y+h-margin-i-1);
g.drawLine(x+w-margin-i-1, y+margin+i, x+w-margin-i-1, y+h-margin-i-1);
}
/**
* Update applet. This method is called in response to a call to repaint.
* Overridden from java.awt.Component to not clear background.
*/
public void update(Graphics g)
{
paint(g);
}
/**
* Update one frame of animation
*
*/
void updateAnimation()
{
if (!initiated) {
return;
}
long tm = 0;
if (debug)
tm = System.currentTimeMillis();
// get size of applet
Dimension d = size();
// Create the offscreen graphics context if required
if ((offImage == null) ||
(d.width != offSize.width) ||
(d.height != offSize.height)) {
// create off-screen graphics context
offSize = d;
offImage = createImage(d.width, d.height);
// reset Animated Text item
currentObj.reset();
}
Graphics offGraphics = offImage.getGraphics();
int margin = getMargin();
// init text area size
animAreaSize = new Dimension(d.width-(2*margin),
d.height-(2*margin));
// paint frame
offGraphics.setColor(getBackground());
offGraphics.fillRect(0, 0, d.width, d.height);
drawFrame(offGraphics,
0, 0, d.width, d.height,
frameType, frameWidth, frameMargin);
// from here on just manipulate the text area, using a
// clip rectangle.
offGraphics.clipRect(margin, margin,
animAreaSize.width, animAreaSize.height);
// reset text background
offGraphics.setColor(getBackground());
offGraphics.fillRect(frameMargin+frameWidth, frameMargin+frameWidth,
animAreaSize.width, animAreaSize.height);
if (bgImage != null) {
if ((mediaTracker.statusID(0, true) & MediaTracker.COMPLETE) != 0) {
// background image loaded; paint it
paintTiledImage(offGraphics, bgImage, frameMargin+frameWidth,
animAreaSize.width, animAreaSize.height);
}
else if (mediaTracker.isErrorID(0)) {
System.out.println("Error: Can't load bgImage");
bgImage = null;
}
}
// animate text
animate(offGraphics);
offGraphics.dispose();
dbg("time for updateAnimation():" + (System.currentTimeMillis() - tm));
}
/**
* Run the loop. This method is called by class Thread.
*/
public void run() {
if (Thread.currentThread() == thread) {
thread.setPriority(Thread.MIN_PRIORITY);
if (!initiated) {
// init parameters, once!
// But first, init "loading..." message
initLoadMessage();
// Repaint, to display "loading..." message
repaint();
// sleep to allow the "loading.." message to be painted
try {
Thread.sleep(50);
} catch (InterruptedException e) {}
initParameters();
}
}
while (Thread.currentThread() == thread) {
// Update one frame of animation
updateAnimation();
// Repaint. I.e call update() to paint background image
repaint();
// Delay depending on how far we are behind (to assure
// we really delay as much as requested).
try {
threadStartTime += threadDelay;
int delay = (int) Math.max(
threadDelay/2, threadStartTime - System.currentTimeMillis());
dbg("Sleep:" + delay);
Thread.sleep(delay);
} catch (InterruptedException e) {
break;
}
// reload data from URL if required
if (lineData != null && updateInterval > 0) {
if (animateCount >= updateInterval) {
// reaload line data from URL
dbg("Re-init data from URL");
animateCount = 0;
Vector lineVector = new Vector();
initLineParametersFromInputURL(
lineData, lineVector, urlStrings);
createAnimates(lineVector, font,
getForeground(), getBackground(),
dx, dy, delim);
}
}
}
}
/**
* Start the applet by forking an animation thread.
*/
public void start() {
repaint();
if (thread == null) {
// create new animate thread (using thread-group saved in init)
if (threadGroup != null)
thread = new Thread(threadGroup, this);
else
thread = new Thread(this);
thread.start();
}
// remember the thread start time
threadStartTime = System.currentTimeMillis();
}
/**
* Stop the applet. The thread will exit because run() exits.
*/
public void stop() {
thread = null;
}
/**
* Take care of mouse-up event to handle Suspend/Resume
* and to show about info.
*/
public boolean mouseUp(Event evt, int x, int y) {
if ((evt.modifiers & Event.SHIFT_MASK) != 0) {
showAboutPopup();
return true;
}
String urlString = null;
if (currentObjectIndex < urlStrings.size())
urlString = (String) urlStrings.elementAt(currentObjectIndex);
// handle Suspend/Resume
// Note: Netscape 3.0 doesnt like Thread.suspend() so, im
// now existing the thread instead...
if (suspended || thread == null) {
start();
suspended = false;
}
else if (urlString == null) {
stop();
suspended = true;
}
if (suspended)
// show version when suspended (sneak promotion ;-)
showStatus(getAppletInfo() + " - Click to resume.");
else {
if (urlString != null) {
// show document as specified in urlString
showDocument(urlString);
}
else {
// sneak advertising and about about popup...
if (showAbout)
showStatus(getAppletInfo() + " - Shift-click for info...");
else
showStatus(getAppletInfo());
}
}
return true;
}
/**
* Take care of mouse-enter event to handle show URL (if specified)
*/
public boolean mouseEnter(Event evt, int x, int y) {
showUrl();
return true;
}
/**
* Display "about" popup frame
*/
void showAboutPopup() {
if (!showAbout)
return;
FunScrollAbout about = new FunScrollAbout(getAppletInfo());
about.appendText("\t" + getAppletInfo() + "\n\n");
about.appendText(" Copyright (c) 1996, 1997 by " +
"Jan Andersson, Torpa Konsult AB.\n\n");
about.appendText(" Info, updates and documentation at " +
sourceLocation + "\n\n");
about.appendText(" Applet information:\n");
about.appendText(" Document base: " + getDocumentBase()+"\n");
about.appendText(" Code base: " + getCodeBase()+"\n\n");
about.appendText(" Applet parameters:\n");
about.appendText(" width = " + getParameter("WIDTH")+"\n");
about.appendText(" height = " + getParameter("HEIGHT")+"\n\n");
// Display parameter info
about.appendText(" Message lines (line<n> parameters):\n");
for (int i = 0; i < noOfObjects; i++) {
FunScrollAnimate txt = (FunScrollAnimate)
animatedObjects.elementAt(i);
about.appendText(" line" + i +" = " +
txt.getUnparsedTextLine() + "\n");
about.appendText(" url" + i +" = ");
String urlString = null;
if (i < urlStrings.size())
urlString = (String) urlStrings.elementAt(i);
about.appendText(urlString + "\n");
}
about.appendText("\n Other parameters:\n");
String params[][] = getParameterInfo();
for (int i = 2; i < params.length; i++) {
String parInfo = " " + params[i][0] + " = " +
getParameter(params[i][0]);
if (parInfo.length() <= 17)
parInfo += "\t";
about.appendText(parInfo + "\t [" + params[i][2] + "]\n");
}
about.show();
}
/**
* Display current url in status line.
*/
void showUrl() {
// display current url if specified
if (urlStrings != null && currentObjectIndex < urlStrings.size()) {
String urlString =
(String) urlStrings.elementAt(currentObjectIndex);
if (urlString != null) {
String tmp = urlString.toUpperCase();
int tIndex = tmp.indexOf("TARGET=");
if (tIndex > 0)
urlString = urlString.substring(0, tIndex);
showStatus(urlString);
}
else
showStatus("");
}
}
/**
* Show document as specified in URL string
*/
void showDocument(String urlString) {
// check if target option specified in URL string
String target = null;
String tmp = urlString.toUpperCase();
int tIndex = tmp.indexOf("TARGET=");
if (tIndex > 0) {
target = urlString.substring(tIndex+7);
urlString = urlString.substring(0, tIndex);
target = target.trim();
dbg("target:" + target);
}
if (target == null)
// use target provided as parameter
target = urlTarget;
// try URL directly
URL url = null;
try {
url = new URL(urlString);
}
catch (MalformedURLException e) {
//System.out.println(e.getMessage());
url = null;
}
if (url == null) {
// try to get url in context of current document
try {
url = new URL(getDocumentBase(), urlString);
}
catch (MalformedURLException e) {
System.out.println("Error. Can't open URL: " + urlString);
System.out.println("(" + e.getMessage() + ")");
showStatus("Error. Can't open URL: " + urlString);
url = null;
}
}
// Load URL, using showDocument()
if (url != null) {
showStatus("Loading: " + urlString + "...");
if (target == null)
getAppletContext().showDocument(url);
else
getAppletContext().showDocument(url, target);
}
}
/**
* Simple debug...
*/
static public void dbg(String str) {
if (debug) {
System.out.println("Debug: " + str);
System.out.flush();
}
}
/**
* Get offscreen image
*/
public Image getOffImage()
{
return offImage;
}
/**
* Get applet frame margin
*/
public int getMargin()
{
return frameMargin+frameWidth;
}
/**
* Returns a darker version of color.
*/
static Color darker(int r, int g, int b, double factor) {
return FunScrollColorSupport.darker(r, g, b, factor);
}
/**
* Returns a darker version of color.
*/
static Color darker(Color c, double factor) {
return FunScrollColorSupport.darker(c, factor);
}
/**
* Returns a brighter version of color.
*/
static Color brighter(int r, int g, int b, double factor) {
return FunScrollColorSupport.brighter(r, g, b, factor);
}
/**
* Returns a brighter version of color.
*/
static Color brighter(Color c, double factor) {
return FunScrollColorSupport.brighter(c, factor);
}
}