/*----------------------------------------------------------------------*/ /* Btex -- animates text into a box with psuedo-tex soon to become respectable code... **based on James Gosling's DancingText.java (in this dir) */ /*----------------------------------------------------------------------*/ /* public variables fontName="TimesRoman36bi" style=..0-7 means {none, starburst, stage right shuffle, stage left shuffle , slide in from right, reverse order, alternate sides, random} time=4000 ..time it takes to finsih animation sound= the URL of a sound (played after animation) delay= time between frames (50 is default) pause= pause before the animation starts amplitude=36 ..amplitude of the wave in pixels length=1 .. a multiplier for the wave length trans=15 ..translates the wave--use to get the right end position foreground=awt.Color.blue background=awt.Color.lightGray box = true ..draw a box around the text centre = true ..centre text y_space = 1 ..vertical spacing more thanfont height x,y = position in window xborder, yborder = blank space around the window (text formating) */ /*----------------------------------------------------------------------*/ /* If you want to do some custom animation for the text I have marked easy spots for customization with "**" in the comments (namely at the initial position, timing function (I like sqrt), and the algorithm (this one is a linear combination of the initial and the final positions with a wave in the y direction) */ /*----------------------------------------------------------------------*/ /* I left the original audio code in (commented out) but I can't use it since I don't have a speaker */ /*----------------------------------------------------------------------*/ /* Jim Morey - morey@math.ubc.ca - Aug 31 */ /*----------------------------------------------------------------------*/ /* ** Warning this code is a complete mess! check http://www.math.ubc.ca/~morey/morey.html for much better coding -- I'll clean this up when I get some time. When I get a stable version I'll do some documentation too I'm wondering what direction I want to go with this...Do I want start over and code a simple Tex have the strings of Tex able to be loaded from files. Then a unix filter could do replacement for macros. That would save programing... */ /*----------------------------------------------------------------------*/ import java.io.InputStream; import awt.*; import browser.*; import browser.audio.AudioData; import net.www.html.*; /*----------------------------------------------------------------------*/ class line{ public int x1,y1,x2,y2,colour; } class letter{ public int x,y,font,colour,c; letter(){ } } class format_state{ public int start_index, start_let,x_start,y_top,y_bottom,y_base,font,colour, subfont,fracfont,next; format_state(){ } } /*----------------------------------------------------------------------*/ class Btex implements Runnable{ int x,y,time,delay,pause,style,amplitude,trans,xborder,yborder,y_space=2; int num_fonts,num_colours; float length; Color foreground[], background = null; String audioName; String fontName[]; boolean fetchingAudio, playRequested, ready=false, keep_going, box; boolean centre; private int t0,W,H,len,num_let,num_lines; private Graphics offscreen; private Image im; private Font thefont[], font; private Applet parent; private AudioData ad; private letter letters[]; private line lines[]; /* - - - - - - - - - - - - - - - - - - - - - - */ Btex(Applet parent,int wid, int heig) { this.parent = parent; time = 1000; background = awt.Color.lightGray; delay = 50; amplitude = 0; trans = 0; length = 5.0; pause = 0; style = 1; x = 0; y = 0; xborder=0; yborder=0; box = false; centre = false; W = wid; H = heig; im = parent.createImage(W,H); offscreen = new Graphics(im); offscreen.setForeground(background); offscreen.fillRect(0, 0, W, H); } /* - - - - - - - - - - - - - - - - - - - - - - */ public void setup_words(String s){ /* .. format the final postions of the Btex .. */ /* .. worry about all the font stuff I should probably just input it direct rather than chop up a string but if it ain't broke... .. */ int i,j,k,c,x_cur; int entry; String temp; format_state st[], wrap; thefont = new Font[num_fonts]; for (i=0;i 0) { c = fontName[i].charAt(--pos); switch (c) { case 'b': fstyle |= Font.BOLD; continue; case 'i': fstyle |= Font.ITALIC; continue; case 'u': fstyle |= Font.UNDERLINE; continue; } break; } int fac = 1; while ('0' <= c && c <= '9') { size += (c - '0') * fac; if (--pos <= 0) break; c = fontName[i].charAt(pos); fac = fac * 10; } if (size <= 0) size = 24; fontName[i] = fontName[i].substring(0, pos + 1); thefont[i] = parent.getFont(fontName[i], fstyle, size); if (thefont[i] == null) { thefont[i] = font; System.out.println("Btex: did not find font" + fontName[i]); } else font = thefont[i]; } if (box) { /* .. make room for the box unless other borders were picked .. */ if (xborder == 0 && yborder ==0){ xborder=4; yborder=4; } } /* .. let's have some TEX .. */ if (s == null) s = "nothing to say"; len = s.length(); letters = new letter[len]; for(i=0;ixmax) xmax = x_cur; x_cur += thefont[st[lev].font].charWidth(c); } else if (c == '/') { switch (st[lev].next){ case -1: System.out.println("Btex: Finished the main state?!?!! "+ i); break; case 0: lev--; break; case 1: st[lev].next = 0; lev++; st[lev].font = st[lev-1].fracfont; st[lev].subfont = st[lev-1].subfont; st[lev].fracfont = st[lev-1].fracfont; st[lev].colour = st[lev-1].colour; st[lev].start_let = num_let; st[lev].x_start = st[lev-1].x_start; st[lev-1].x_start = x_cur; x_cur = st[lev].x_start; st[lev].y_top = st[lev-2].y_base - thefont[st[lev-2].font].ascent/2; st[lev].y_base = st[lev].y_top + thefont[st[lev].font].ascent; st[lev].y_bottom = st[lev].y_base; st[lev].next = 2; break; case 2: /* .. centre .. */ dx = x_cur - st[lev-1].x_start; if (dx>0){ for(j=st[lev-1].start_let;js.length()) j = s.length(); temp = s.substring(i+1,j); /* .. change this for long commands .. */ /* . . . . . . . . . . . . . . . . . . */ if (temp.indexOf("subfont")==0){ i += 7; c = s.charAt(i+1); entry = 0; while ('0' <= c && c <= '9') { entry = entry*10+ c -'0'; i++; c = s.charAt(i+1); } if (entry0) if (lev ==0){ st[0].y_base += dy; st[0].y_bottom += dy; st[0].y_top = st[0].y_base-thefont[st[0].font].ascent; for (k=st[0].start_let;k<=i;k++) letters[k].y += dy; } else st[lev].y_top -= dy; } } /* . . . . . . . . . . . . . . . . . . */ else if (temp.indexOf("colour")==0){ i += 6; c = s.charAt(i+1); entry = 0; while ('0' <= c && c <= '9') { entry = entry*10+ c -'0'; i++; c = s.charAt(i+1); } if (entryxmax) xmax = x_cur; x_cur = 0; lev = 0; wrap.start_index = i; wrap.font = st[0].font; wrap.fracfont = st[0].fracfont; wrap.subfont = st[0].subfont; wrap.colour = st[0].colour; wrap.start_let = st[0].start_let; wrap.y_bottom = st[0].y_bottom; } /* . . . . . . . . . . . . . . . . . . */ else System.out.println("unparsed-- " + temp); } else{ dump_letter = true; letters[num_let].c = c; letters[num_let].font = st[lev].font; } /* .. change the y_top and y_bottom if necessary this became messy when 'frac' was implemented.. */ boolean again = true; while (again){ again = false; for (j=lev-1;j>=0;j--) if (st[lev].y_top < st[j].y_top){ if (st[j].next == -1 || st[j].next == 2){ dy = st[j].y_top - st[lev].y_top; for (k=j;k<=lev;k++){ st[k].y_base += dy; st[k].y_bottom += dy; } st[lev].y_top += dy; for (k=st[j].start_let;k<=i;k++) letters[k].y += dy; } } else j=-1; for (j=lev-1;j>=0;j--) if (st[lev].y_bottom >st[j].y_bottom){ if (st[j].next == -1) { st[j].y_bottom = st[lev].y_bottom; } else if (st[j].next ==1){ again = true; /* .. in case the fraction gets pushed up .. */ dy = st[j].y_base - st[lev].y_bottom; for (k=j;k<=lev;k++){ st[k].y_top += dy; st[k].y_base += dy; st[k].y_bottom += dy; } st[lev].y_bottom += dy; for (k=st[j].start_let;k<=i;k++) letters[k].y += dy; } } else j=-1; } if (dump_letter){ /* .. put a letter .. */ letters[num_let].x = x_cur; x_cur += thefont[st[lev].font].charWidth(letters[num_let].c); letters[num_let].y = st[lev].y_base; letters[num_let].colour = st[lev].colour; num_let++; if (x_cur>W-2*xborder) { /* .. we need to wrap ** need to check that it doesn't wrap an wrap etc .. */ if (wrap.start_index == st[0].start_index) { System.out.println("Btex --line too long" + i); i = len; } else { lev = 0; st[0].font = wrap.font; st[0].subfont = wrap.subfont; st[0].fracfont = wrap.fracfont; st[0].colour = wrap.colour; st[0].start_index = wrap.start_index; st[0].y_top = wrap.y_bottom+y_space; st[0].y_base = st[0].y_top + thefont[st[0].font].ascent; st[0].y_bottom = st[0].y_base; st[0].start_let = wrap.start_let; st[0].x_start = 0; num_let = wrap.start_let; x_cur = 0; i= st[0].start_index; wrap.y_bottom = st[0].y_bottom; } } } } if (x_cur>xmax) xmax = x_cur; /* .. centre the whole block if desired .. */ if (centre){ dy = (H-st[0].y_bottom)/2-yborder; dx = (W-xmax)/2-xborder; for (i = 0; i < num_let; i++) { letters[i].x += dx; letters[i].y += dy; } } } /* - - - - - - - - - - - - - - - - - - - - - - */ public void run(){ Thread.currentThread().setPriority(Thread.MIN_PRIORITY); int x0[],y0[], xco,yco; char junk[]; /* .. I can't play with this stuff since I don't have a speaker .. if (audioName != null && !fetchingAudio) { fetchingAudio = true; kicker = new Thread(this); kicker.start(); Thread.currentThread().setPriority(Thread.MIN_PRIORITY); ad = getAudioData(audioName); if (playRequested) play(ad); return; } if (ad != null) play(ad); else playRequested = true; */ /* .. get a blank window to draw the text .. */ offscreen.setForeground(background); if (box) offscreen.paint3DRect(1, 1, W-3, H-3,true,true); else offscreen.fillRect(0, 0, W, H); offscreen.setForeground(foreground[0]); x0 = new int[num_let]; y0 = new int[num_let]; junk = new char[2]; /* .. **there is a lot of room to have new start positions .. */ switch (style) { default: case 0: /* .. still .. */ for (int i = 0; i < num_let; i++) { x0[i] = letters[i].x; y0[i]=letters[i].y;} break; case 1: /* .. below and away .. */ for (int i = 0; i < num_let; i++) { x0[i] = W/2; y0[i]=H*2;} break; case 2: /* .. stretch from the right .. */ for (int i = 0; i < num_let; i++) { x0[i] = W; y0[i]=letters[i].y; } break; case 3: /* .. stretch form the left .. */ for (int i = 0; i < num_let; i++){ x0[i] = 0; y0[i]=letters[i].y; } break; case 4: /* .. slide in from the right .. */ for (int i = 0; i < num_let; i++){ x0[i] = letters[i].x + W; y0[i]=letters[i].y; } break; case 5: /* .. in 2 dimension this one is not too predictable .. */ for (int i = 0; i < num_let; i++){ x0[i] = letters[num_let - i - 1].x; y0[i]=letters[i].y; } break; case 6: /* .. stretch from both sides .. */ for (int i = 0; i < num_let; i++){ x0[i] = (i & 1) == 0 ? W : 0; y0[i]=letters[i].y; } break; case 7: /* .. random .. */ for (int i = 0; i < num_let; i++){ x0[i] = (int) (W * Math.random()); y0[i]=(int) (H*Math.random()); } break; } t0 = System.nowMillis(); float wave; keep_going=true; while (keep_going) { ready = false; offscreen.setForeground(background); if (box) offscreen.paint3DRect(0, 0, W, H,true,true); else offscreen.fillRect(0, 0, W, H); offscreen.setForeground(foreground[0]); int t = System.nowMillis() - t0; wave = 1.0; if (t > time) keep_going=false; /* .. **lots of possibilities for timing functions .. */ else wave = (float) Math.sqrt((double)t/(double)time); for (int i = 0; i < num_let; i++) { /* .. **lots of possibilities for algorthims too .. */ offscreen.setForeground(foreground[letters[i].colour]); xco = (int) (wave*letters[i].x + (1-wave)*x0[i] +xborder); yco = (int) (wave*letters[i].y + (1-wave)*y0[i] +yborder) + (int) (amplitude * Math.sin(3.14* (letters[i].x/length+wave*100+trans)/16) ); if (letters[i].c != -1){ junk[0] = (char)letters[i].c; offscreen.setFont(thefont[letters[i].font]); offscreen.drawChars(junk, 0, 1 ,xco,yco); } else offscreen.drawLine(xco,yco,xco+letters[i].font,yco); } ready = true; parent.repaint(); Thread.sleep(delay); } } /* - - - - - - - - - - - - - - - - - - - - - - */ public void paint(Graphics g) { if (ready) g.drawImage(im, x, y); } } /*----------------------------------------------------------------------*/