/* Program : Teletype.java * Purpose : Web Text Display Applet * Author : Bill Boulton * Date : June 12, 1997 * Final Revision July 15 1997 * Version : 1.3 * email : boulton@amadeus.ccs.queensu.ca * Terms : Distribution of this source is being made in the hope that it may be found useful. It can be freely modified and redistributed provided this entire notice is left on the redistribution. * You'll notice that where code is used which was * modified from other source the authors are referenced * as a courtesy and in appreciation of their efforts * to promote "Public Domain" software and the understanding * of the Java Language. */ import java.applet.*; import java.awt.*; import java.util.*; import java.awt.image.*; public class teletype extends Applet implements Runnable{ String Message[]; int MaxLines; int Columns = 0; int NumLines = 0; char Screen[][]; /* array Malines Columns */ int YLinePos[]; String FontColor; String ImageLoadMessage; int CursorX; int CursorY; int Index=0; int Xlimit=0,LoopCount=0, ArrayCount=0; Thread Life=null; char DisplayMessage[]; String ScrollParam; boolean ScrollFlag = true; boolean set = false; String BackgroundImage; Image Tube; boolean ImageAvailable = false; Color BackColor; String Bgcolor; String MessageParms; /* Have the user supply the number of messages */ int NumMessages; /* Valid between 1 and 5 (msg0 to msg4). */ /**************************/ /* */ /* Offscreen graphics */ /* Variables */ /* */ /**************************/ Image FinalScreen; Graphics osg; /**************************/ /* */ /* Screen graphics */ /* Variables */ /* */ /**************************/ Graphics g; boolean initComplete = false; /**************************/ /* Font Variables */ /**************************/ Font Screen_Font; Font normalFont; FontMetrics fm; Color Screen_Font_Color; /* Parameter from html tag */ private int charWidth; private int charHeight; private int charDescent; private int LineFeed; /************************/ /* Screen Margins */ /************************/ private int TopMargin; private int LeftMargin; private int RightMargin; private int BottomMargin; /*****************************************/ /* Variabeles used to wrap the Messages */ /* to which fit into the Display */ /* area. */ /*****************************************/ StringBuffer sb = new StringBuffer(); StringTokenizer st; String Line[]; public void init(){ BackgroundImage =getParameter("bgImage"); g=this.getGraphics(); MessageParms = getParameter("Msgnum"); NumMessages =(MessageParms ==null)? 2 :Integer.parseInt(MessageParms); Message = new String[NumMessages]; Message[0] = getParameter("Msg0"); if (NumMessages > 1) Message[1] = getParameter("Msg1"); if (NumMessages > 2) Message[2]= getParameter("Msg2"); if (NumMessages > 3) Message[3]= getParameter("Msg3"); if (NumMessages > 4) Message[4]= getParameter("Msg4"); ImageLoadMessage="Loading Image"; resize(size().width, size().height); Screen_Font= initFont(); setFont(Screen_Font); fm = getFontMetrics(Screen_Font); if(fm != null) { charWidth = fm.charWidth(' '); charHeight = fm.getHeight(); charDescent = fm.getDescent(); } LineFeed = charHeight + 1; LeftMargin = 18; RightMargin = size().width - 15; TopMargin = 32; BottomMargin = size().height - 25; CursorY = TopMargin; CursorX = LeftMargin; MaxLines = (size().height - TopMargin) / (LineFeed); YLinePos = new int[MaxLines]; /*************************************************/ /* */ /* Set up the Line Y positions. */ /* These positions are used by the Insert */ /* Line routine to draw the Strings */ /* */ /*************************************************/ for (LoopCount = 0; LoopCount 0) { if (Columns < sb.length()) Columns = sb.length(); } sb = new StringBuffer(); nextword = " " ; } /*************************************************/ /* This routine is passed a string. It then */ /* wraps the string by measuring the string */ /* and comparing it to the Display width . */ /* Each time the message is parsed the substring */ /* is fed to the data output routine Typer() */ /*************************************************/ public void Process_Line(String Input_String) { String nextword; st = new StringTokenizer(Input_String," "); while (st.hasMoreTokens()) { nextword = st.nextToken(); if (fm.stringWidth(sb.toString() + nextword) < (RightMargin - LeftMargin)) { sb.append(nextword); sb.append(' '); } else if (sb.length() == 0) { Typer(nextword); /* catches the one word case */ } else { Typer(sb.toString()); sb = new StringBuffer(nextword + " "); } } // end While if (sb.length() > 0) { Typer(sb.toString()); } sb = new StringBuffer(); nextword = " "; } /*************************************************/ /* This routine is passed the Graphics class */ /* it performas an arraycopy using nested for */ /* loops. The System.arraycopy should work */ /* but created some problems for me. This */ /* source is my solution and should be easily */ /* adapted for handling two dimesional arrays */ /* for other display techniques. */ /* All Rights to this routine are mine */ /*************************************************/ public void InsertLine(Graphics g) { int Lcount,Rcount; char Temp; char ScrBuff[][] = new char[MaxLines][Columns]; /* Start with each element in the array set to " ". */ /* This is necessary for Micorsofts Internet Explorer. */ /* IE set's each element to null ......... */ try { for(Lcount = 0; Lcount <=MaxLines;Lcount++) for(Rcount = 0; Rcount <=Columns - 1 ;Rcount++) { Temp = ' '; ScrBuff[Lcount][Rcount] = Temp; } } catch (ArrayIndexOutOfBoundsException e){} /* That should fix MIE problem */ try { for(Lcount = 1; Lcount <=MaxLines;Lcount++) for(Rcount = 0; Rcount <=Columns - 1 ;Rcount++) { Temp = Screen[Lcount][Rcount]; ScrBuff[Lcount-1][Rcount] = Temp; } } catch (ArrayIndexOutOfBoundsException e){} try { for(Lcount = 0; Lcount <=MaxLines-1;Lcount++) for(Rcount = 0; Rcount <=Columns - 1 ;Rcount++) { Temp = ScrBuff[Lcount][Rcount]; Screen[Lcount][Rcount] = Temp; } } catch (ArrayIndexOutOfBoundsException e){} int insCount; if(!ImageAvailable) osg.drawImage(Tube,0,0,size().width,size().height,this); else offsnoImage(); for (insCount = 1; insCount <= MaxLines - 1; insCount ++) { osg.drawChars(Screen[insCount -1],0,Columns,CursorX,YLinePos[insCount - 1]); } g.drawImage(FinalScreen,0,0,this); /* Stop Screen Flashing */ CursorX = LeftMargin; if(!ImageAvailable) osg.drawImage(Tube,0,0,size().width,size().height,this);/* clear offscreen */ else offsnoImage(); NumLines = MaxLines-1; try {Thread.sleep(400);} catch (InterruptedException e){} } // end Insert Line Routine /********************************************/ /* This is the scroll routine which can be */ /* used at the end of each message to scroll*/ /* the characters off the screen. This */ /* routine is also the basis for the Vertical*/ /* Scroller class here. */ /********************************************/ public void scroller(Graphics g) { int offset = charHeight / 5; int scrollcount; CursorX = LeftMargin; osg.setFont(Screen_Font); osg.setColor(Screen_Font_Color); while((YLinePos[NumLines]- offset) >= - charHeight) { if(!ImageAvailable) osg.drawImage(Tube,0,0,size().width,size().height,this); else offsnoImage(); for (scrollcount = 0;scrollcount <=NumLines; scrollcount++) { if (YLinePos[scrollcount] - offset >= - LineFeed) osg.drawChars(Screen[scrollcount],0,Columns,CursorX,(YLinePos[scrollcount]-offset)); } //end for offset = offset + charHeight/5; g.drawImage(FinalScreen,0,0,this); try {Thread.sleep(200);} catch (InterruptedException e){} } // end while } // end scroller /************************************************/ /* This is the routine that actually does the */ /* data output tasks. This is my soulution to */ /* the typing text display technique. */ /************************************************/ public void Typer(String InString) { int pcount = 0; int NumChars = 0; int TCursorX = LeftMargin; CursorX = LeftMargin; if(Life != null) { Graphics g = this.getGraphics(); g.setColor(Screen_Font_Color); Xlimit = InString.length() - 1; DisplayMessage = InString.toCharArray(); for (NumChars = 0;NumChars YLinePos[MaxLines -1]) { InsertLine(g); CursorY = YLinePos[MaxLines -1]; CursorX = LeftMargin; } else NumLines++; CursorX = LeftMargin; if(Life !=null) /*Try to catch having left page during the for loop */ { try {Thread.sleep(100);} catch (InterruptedException e){} } } // end if !done } /* end Typer*/ public void paint(Graphics g){ /****************************************************************/ /* The loadImageAndWait delay is required to process the image */ /* before characters are displayed . The image is then */ /* drawn on the display. */ /****************************************************************/ int pcount; int ThisCursorX = LeftMargin; g.setFont(Screen_Font); g.setColor(Screen_Font_Color); if(getParameter("bgImage") != null) { Tube = getImage(getDocumentBase(),BackgroundImage); if (!set) { g.drawString(ImageLoadMessage,20,20); loadImageAndWait(Tube); /* Prepare image before routines start */ initscreen(); set = true; initComplete = true; } } else { ImageAvailable = true; offsnoImage(); set = true; initComplete = true; } if (initComplete) g.drawImage(FinalScreen,0,0,this); /**************************************************/ /* If the users scrolls down the page and returns */ /* to the applet the entire screen and data are */ /* reconstructed. */ /**************************************************/ for (pcount = 0; pcount <= MaxLines - 1; pcount ++) { g.drawChars(Screen[pcount],0,Columns,ThisCursorX,YLinePos[pcount]); } } public void update(Graphics g){ paint(g); }//end update public String getAppletInfo() { return "teletype / thetube version 1.3 written by Bill Boulton"; } /***************************************************************/ /* */ /* The Following two routines were "borrowed" from the creator */ /* of Instant Java. The site where this and much more code is */ /* available is www.vivids.com. */ /* These routines get rid of that pesky image not loaded before*/ /* charcters are displayed problem that has plagued me. */ /* Many thanks to the author of this code. */ /* */ /***************************************************************/ /** * Begins the preparation (loading) of the image * This function returns immediately * The image is loaded in a thread * * @param image the image to prepare */ public void prepareImage(Image image) { boolean ImagePrepared; ImagePrepared = prepareImage(image, this); } public synchronized void loadImageAndWait(Image image) { int checkImageFlags; boolean ImagePrepared; ImagePrepared = prepareImage(image, this); if(ImagePrepared == false) { while(((checkImageFlags = checkImage(image, this)) & ImageObserver.ALLBITS) == 0) { try { wait(100); } catch (InterruptedException e){} } } } } // end theTube