KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > Animator


1 /*
2  * @(#)Animator.java 1.15 06/02/22
3  *
4  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * -Redistribution of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  *
12  * -Redistribution in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
17  * be used to endorse or promote products derived from this software without
18  * specific prior written permission.
19  *
20  * This software is provided "AS IS," without a warranty of any kind. ALL
21  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
22  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
24  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
25  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
26  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
27  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
28  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
29  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * You acknowledge that this software is not designed, licensed or intended
33  * for use in the design, construction, operation or maintenance of any
34  * nuclear facility.
35  */

36
37 /*
38  * @(#)Animator.java 1.15 06/02/22
39  */

40
41 import java.awt.*;
42 import java.awt.event.*;
43 import java.applet.Applet JavaDoc;
44 import java.applet.AudioClip JavaDoc;
45 import java.util.Vector JavaDoc;
46 import java.util.Hashtable JavaDoc;
47 import java.util.Enumeration JavaDoc;
48 import java.net.URL JavaDoc;
49 import java.net.MalformedURLException JavaDoc;
50 import java.util.List JavaDoc;
51 import java.util.ArrayList JavaDoc;
52 import java.util.Iterator JavaDoc;
53
54 /**
55  * An applet that plays a sequence of images, as a loop or a one-shot.
56  * Can have a soundtrack and/or sound effects tied to individual frames.
57  * See the <a HREF="http://java.sun.com/applets/applets/Animator/">Animator
58  * home page</a> for details and updates.
59  *
60  * @author Herb Jellinek
61  * @version 1.15, 02/22/06
62  */

63 public class Animator extends Applet JavaDoc implements Runnable JavaDoc, MouseListener {
64     int appWidth = 0; // Animator width
65
int appHeight = 0; // Animator height
66
Thread JavaDoc engine = null; // Thread animating the images
67
boolean userPause = false; // True if thread currently paused by user
68
boolean loaded = false; // Can we paint yet?
69
boolean error = false; // Was there an initialization error?
70
Animation animation = null; // Animation this animator contains
71
String JavaDoc hrefTarget = null; // Frame target of reference URL if any
72
URL JavaDoc hrefURL = null; // URL link for information if any
73

74     static final String JavaDoc sourceLocation =
75                           "http://java.sun.com/applets/applets/Animator/";
76     static final String JavaDoc userInstructions = "shift-click for errors, info";
77     static final int STARTUP_ID = 0;
78     static final int BACKGROUND_ID = 1;
79     static final int ANIMATION_ID = 2;
80
81     /**
82      * Applet info.
83      */

84     public String JavaDoc getAppletInfo() {
85     return "Animator v1.10 (02/05/97), by Herb Jellinek";
86     }
87
88     /**
89      * Parameter info.
90      */

91     public String JavaDoc[][] getParameterInfo() {
92     String JavaDoc[][] info = {
93         {"imagesource", "URL", "a directory"},
94         {"startup", "URL", "image displayed at start-up"},
95         {"backgroundcolor", "int", "background color (24-bit RGB number)"},
96         {"background", "URL", "image displayed as background"},
97         {"startimage", "int", "index of first image"},
98         {"endimage", "int", "index of last image"},
99         {"namepattern", "URL", "generates indexed names"},
100         {"images", "URLs", "list of image indices"},
101         {"href", "URL", "page to visit on mouse-click"},
102         {"target", "name", "frame to put that page in"},
103         {"pause", "int", "global pause, milliseconds"},
104         {"pauses", "ints", "individual pauses, milliseconds"},
105         {"repeat", "boolean", "repeat? true or false"},
106         {"positions", "coordinates", "path images will follow"},
107         {"soundsource", "URL", "audio directory"},
108         {"soundtrack", "URL", "background music"},
109         {"sounds", "URLs", "list of audio samples"},
110     };
111     return info;
112     }
113
114     /**
115      * Show a crude "About" box. Displays credits, errors (if any), and
116      * parameter values and documentation.
117      */

118     void showDescription() {
119     DescriptionFrame description = new DescriptionFrame();
120     description.tell("\t\t"+getAppletInfo()+"\n");
121     description.tell("Updates, documentation at "+sourceLocation+"\n\n");
122     description.tell("Document base: "+getDocumentBase()+"\n");
123     description.tell("Code base: "+getCodeBase()+"\n\n");
124     
125     Object JavaDoc errors[] = animation.tracker.getErrorsAny();
126     if (errors != null) {
127         description.tell("Applet image errors:\n");
128         for (int i = 0; i < errors.length; i++) {
129         if (errors[i] instanceof Image) {
130             AnimationFrame frame = (AnimationFrame)
131                                               animation.frames.get(i);
132                     URL JavaDoc url = frame.imageLocation;
133             if (url != null) {
134             description.tell(" "+url+" not loaded\n");
135             }
136         }
137         }
138         description.tell("\n");
139     }
140     if (animation.frames == null || animation.frames.size() == 0)
141         description.tell("\n** No images loaded **\n\n");
142     description.tell("Applet parameters:\n");
143     description.tell(" width = "+getParameter("WIDTH")+"\n");
144     description.tell(" height = "+getParameter("HEIGHT")+"\n");
145     String JavaDoc params[][] = getParameterInfo();
146     for (int i = 0; i < params.length; i++) {
147         String JavaDoc name = params[i][0];
148         description.tell(" "+name+" = "+getParameter(name)+
149                  "\t ["+params[i][2]+"]\n");
150     }
151     description.show();
152     }
153
154     /**
155      * Local version of getParameter for debugging purposes.
156      */

157     public String JavaDoc getParam(String JavaDoc key) {
158     String JavaDoc result = getParameter(key);
159     return result;
160     }
161
162     /**
163      * Get parameters and parse them
164      */

165     public void handleParams() {
166         try {
167         String JavaDoc param = getParam("IMAGESOURCE");
168         animation.imageSource = (param == null) ? getDocumentBase() :
169                 new URL JavaDoc(getDocumentBase(), param + "/");
170     
171         String JavaDoc href = getParam("HREF");
172         if (href != null) {
173         try {
174             hrefURL = new URL JavaDoc(getDocumentBase(), href);
175         } catch (MalformedURLException JavaDoc e) {
176             showParseError(e);
177         }
178         }
179
180         hrefTarget = getParam("TARGET");
181         if (hrefTarget == null)
182         hrefTarget = "_top";
183         param = getParam("PAUSE");
184             if (param != null)
185                 animation.setGlobalPause(Integer.parseInt(param));
186         param = getParam("REPEAT");
187         animation.repeat = (param == null) ? true :
188                 (param.equalsIgnoreCase("yes") ||
189                  param.equalsIgnoreCase("true"));
190         int startImage = 1;
191         int endImage = 1;
192         param = getParam("ENDIMAGE");
193         if (param != null) {
194         endImage = Integer.parseInt(param);
195         param = getParam("STARTIMAGE");
196         if (param != null) {
197             startImage = Integer.parseInt(param);
198         }
199                 param = getParam("NAMEPATTERN");
200                 animation.prepareImageRange(startImage, endImage, param);
201         } else {
202         param = getParam("STARTIMAGE");
203         if (param != null) {
204             startImage = Integer.parseInt(param);
205             param = getParam("NAMEPATTERN");
206             animation.prepareImageRange(startImage, endImage, param);
207         } else {
208             param = getParam("IMAGES");
209             if (param == null) {
210             showStatus("No legal IMAGES, STARTIMAGE, or ENDIMAGE "+
211                    "specified.");
212             error = true;
213             return;
214             } else {
215             animation.parseImages(param, getParam("NAMEPATTERN"));
216             }
217         }
218         }
219
220         param = getParam("BACKGROUND");
221         if (param != null)
222         animation.backgroundImageURL = new URL JavaDoc(animation.imageSource,
223                                                        param);
224         param = getParam("BACKGROUNDCOLOR");
225         if (param != null)
226         animation.backgroundColor = decodeColor(param);
227         param = getParam("STARTUP");
228         if (param != null)
229         animation.startUpImageURL = new URL JavaDoc(animation.imageSource,
230                                                     param);
231         param = getParam("SOUNDSOURCE");
232         animation.soundSource = (param == null) ? animation.imageSource :
233                 new URL JavaDoc(getDocumentBase(), param + "/");
234         param = getParam("SOUNDS");
235         if (param != null)
236         animation.parseSounds(param);
237         param = getParam("PAUSES");
238         if (param != null)
239         animation.parseDurations(param);
240         param = getParam("POSITIONS");
241         if (param != null)
242         animation.parsePositions(param);
243         param = getParam("SOUNDTRACK");
244         if (param != null)
245         animation.soundTrackURL = new URL JavaDoc(
246                                           animation.soundSource, param);
247     } catch (MalformedURLException JavaDoc e) {
248         showParseError(e);
249     } catch (ParseException e) {
250         showParseError(e);
251     }
252     }
253
254     private Color decodeColor(String JavaDoc s) {
255     int val = 0;
256     try {
257         if (s.startsWith("0x")) {
258         val = Integer.parseInt(s.substring(2), 16);
259         } else if (s.startsWith("#")) {
260         val = Integer.parseInt(s.substring(1), 16);
261         } else if (s.startsWith("0") && s.length() > 1) {
262         val = Integer.parseInt(s.substring(1), 8);
263         } else {
264         val = Integer.parseInt(s, 10);
265         }
266         return new Color(val);
267     } catch (NumberFormatException JavaDoc e) {
268         return null;
269     }
270     }
271     
272     /**
273      * Initialize the applet. Get parameters.
274      */

275     public void init() {
276         //animation.tracker = new MediaTracker(this);
277
appWidth = getSize().width;
278     appHeight = getSize().height;
279         animation = new Animation(this);
280         handleParams();
281         animation.init();
282     addMouseListener(this);
283         Thread JavaDoc me = Thread.currentThread();
284         me.setPriority(Thread.MIN_PRIORITY);
285         userPause = false;
286     }
287
288     public void destroy() {
289         removeMouseListener(this);
290     }
291
292     void tellLoadingMsg(String JavaDoc file, String JavaDoc fileType) {
293     showStatus("Animator: loading "+fileType+" "+file);
294     }
295
296     void tellLoadingMsg(URL JavaDoc url, String JavaDoc fileType) {
297     tellLoadingMsg(url.toExternalForm(), fileType);
298     }
299
300     void clearLoadingMessage() {
301     showStatus("");
302     }
303     
304     void loadError(String JavaDoc fileName, String JavaDoc fileType) {
305     String JavaDoc errorMsg = "Animator: Couldn't load "+fileType+" "+
306         fileName;
307     showStatus(errorMsg);
308     System.err.println(errorMsg);
309     error = true;
310     repaint();
311     }
312
313     void loadError(URL JavaDoc badURL, String JavaDoc fileType) {
314     loadError(badURL.toExternalForm(), fileType);
315     }
316
317     void showParseError(Exception JavaDoc e) {
318     String JavaDoc errorMsg = "Animator: Parse error: "+e;
319     showStatus(errorMsg);
320     System.err.println(errorMsg);
321     error = true;
322     repaint();
323     }
324
325     /**
326      * Run the animation. This method is called by class Thread.
327      * @see java.lang.Thread
328      */

329     public void run() {
330         Thread JavaDoc me = Thread.currentThread();
331
332         if (animation == null)
333             return;
334         if (animation.frames == null)
335             return;
336         if ((appWidth <= 0) || (appHeight <= 0))
337             return;
338
339     try {
340             animation.startPlaying();
341
342             while (engine == me) {
343                 // Get current frame and paint it, play its sound
344
AnimationFrame thisFrame = (AnimationFrame)
345                                animation.frames.get(animation.currentFrame);
346                 repaint();
347                 if (thisFrame.sound != null)
348                     thisFrame.sound.play();
349
350                 animation.currentFrame++;
351                 // Check if we are done
352
if (animation.currentFrame >= animation.frames.size()) {
353                     if (animation.repeat)
354                         animation.currentFrame = 0;
355                     else return;
356                 }
357
358                 // Pause for duration or longer if user paused
359
try {
360                     Thread.sleep(thisFrame.duration);
361                     synchronized(this) {
362                         while (userPause) {
363                             animation.stopPlaying();
364                             wait();
365                         }
366                     }
367                 } catch (InterruptedException JavaDoc e) {
368                 }
369             }
370         } finally {
371             synchronized(this) {
372                 if (engine == me)
373                     animation.stopPlaying();
374             }
375         }
376     }
377
378     /**
379      * No need to clear anything; just paint.
380      */

381     public void update(Graphics g) {
382     paint(g);
383     }
384
385     /**
386      * Paint the current frame
387      */

388     public void paint(Graphics g) {
389         if (error || ! loaded) {
390             if (animation.startUpImage != null) {
391         if (animation.tracker.checkID(STARTUP_ID)) {
392             if (animation.backgroundColor != null) {
393             g.setColor(animation.backgroundColor);
394             g.fillRect(0, 0, appWidth, appHeight);
395             }
396             g.drawImage(animation.startUpImage, 0, 0, this);
397         }
398         } else {
399         if ((animation.backgroundImage != null) &&
400              (animation.tracker.checkID(BACKGROUND_ID)))
401             g.drawImage(animation.backgroundImage, 0, 0, this);
402         else
403             g.clearRect(0, 0, appWidth, appHeight);
404         }
405         } else {
406             animation.paint(g);
407         }
408     }
409
410     /**
411      * Start the applet by forking an animation thread.
412      */

413     public void start() {
414     engine = new Thread JavaDoc(this);
415     engine.start();
416     showStatus(getAppletInfo());
417     }
418
419     /**
420      * Stop the insanity, um, applet.
421      */

422     public synchronized void stop() {
423         engine = null;
424         animation.stopPlaying();
425         if (userPause) {
426             userPause = false;
427             notify();
428         }
429     }
430
431     /**
432      * Pause the thread when the user clicks the mouse in the applet.
433      * If the thread has stopped (as in a non-repeat performance),
434      * restart it.
435      */

436     public synchronized void mousePressed(MouseEvent event) {
437         event.consume();
438         if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
439             showDescription();
440             return;
441         } else if (hrefURL != null) {
442             // Let mouseClicked handle this.
443
return;
444         } else if (loaded) {
445             userPause = !userPause;
446             if (!userPause) {
447                 animation.startPlaying();
448                 notifyAll();
449             }
450         }
451     }
452
453     public void mouseClicked(MouseEvent event) {
454         if ((hrefURL != null) &&
455             ((event.getModifiers() & InputEvent.SHIFT_MASK) == 0))
456         {
457             // Note: currently ignored by appletviewer
458
getAppletContext().showDocument(hrefURL, hrefTarget);
459         }
460
461         showStatus(getAppletInfo() + " -- " + userInstructions);
462     }
463
464     public void mouseReleased(MouseEvent event) {
465     }
466
467     public void mouseEntered(MouseEvent event) {
468     }
469
470     public void mouseExited(MouseEvent event) {
471     }
472 }
473
474 /**
475  * A class that represents an animation to be displayed by the applet
476  */

477 class Animation extends Object JavaDoc {
478     static final int STARTUP_ID = 0;
479     static final int BACKGROUND_ID = 1;
480     static final int ANIMATION_ID = 2;
481     static final String JavaDoc imageLabel = "image";
482     static final String JavaDoc soundLabel = "sound";
483
484     int globalPause = 1300; // global pause in milliseconds
485
List JavaDoc frames = null; // List holding frames of animation
486
int currentFrame; // Index into images for current position
487
Image startUpImage = null; // The startup image if any
488
Image backgroundImage = null; // The background image if any
489
AudioClip JavaDoc soundTrack = null; // The soundtrack for this animation
490
Color backgroundColor = null; // Background color if any
491
URL JavaDoc backgroundImageURL = null; // URL of background image if any
492
URL JavaDoc startUpImageURL = null; // URL of startup image if any
493
URL JavaDoc soundTrackURL = null; // URL of soundtrack
494
URL JavaDoc imageSource = null; // Directory or URL for images
495
URL JavaDoc soundSource = null; // Directory or URL for sounds
496
boolean repeat; // Repeat the animation if true
497
Image offScrImage; // Offscreen image
498
Graphics offScrGC; // Offscreen graphics context
499
MediaTracker tracker; // MediaTracker used to load images
500
Animator owner; // Applet that contains this animation
501

502     Animation(Animator container) {
503         super();
504         owner = container;
505     }
506
507     void init() {
508         tracker = new MediaTracker(owner);
509         currentFrame = 0;
510         loadAnimationMedia();
511     }
512
513     void setGlobalPause(int pause) {
514         globalPause = pause;
515     }
516
517     /**
518      * Loads the images and sounds involved with this animation
519      */

520     void loadAnimationMedia() {
521         URL JavaDoc badURL;
522         boolean error;
523         try {
524             if (startUpImageURL != null) {
525                 owner.tellLoadingMsg(startUpImageURL, imageLabel);
526                 startUpImage = fetchImageAndWait(startUpImageURL, STARTUP_ID);
527                 if (tracker.isErrorID(STARTUP_ID)) {
528                     owner.loadError(startUpImageURL, "start-up image");
529                 }
530                 owner.repaint();
531             }
532         
533         if (backgroundImageURL != null) {
534              owner.tellLoadingMsg(backgroundImageURL, imageLabel);
535             backgroundImage = fetchImageAndWait(backgroundImageURL,
536                                                     BACKGROUND_ID);
537             if (tracker.isErrorID(BACKGROUND_ID))
538                     owner.loadError(backgroundImageURL,
539                                         "background image");
540         owner.repaint();
541             }
542
543         // Fetch the animation frame images
544
Iterator JavaDoc iterator = frames.iterator();
545             while(iterator.hasNext()) {
546                 AnimationFrame frame = (AnimationFrame) iterator.next();
547                 owner.tellLoadingMsg(frame.imageLocation, imageLabel);
548                 frame.image = owner.getImage(frame.imageLocation);
549                 tracker.addImage(frame.image, ANIMATION_ID);
550                 try {
551                     tracker.waitForID(ANIMATION_ID);
552                 } catch (InterruptedException JavaDoc e) {}
553         }
554
555         if (soundTrackURL != null && soundTrack == null) {
556         owner.tellLoadingMsg(soundTrackURL, imageLabel);
557         soundTrack = owner.getAudioClip(soundTrackURL);
558         if (soundTrack == null) {
559             owner.loadError(soundTrackURL, "soundtrack");
560             return;
561         }
562         }
563
564             // Load the sounds into their frames
565
iterator = frames.iterator();
566             while(iterator.hasNext()) {
567                 AnimationFrame frame = (AnimationFrame) iterator.next();
568                 if (frame.soundLocation != null) {
569                     owner.tellLoadingMsg(frame.soundLocation, soundLabel);
570                     try {
571                         frame.sound = owner.getAudioClip(frame.soundLocation);
572                     } catch (Exception JavaDoc ex) {
573                         owner.loadError(frame.soundLocation, soundLabel);
574                     }
575                 }
576         }
577
578         owner.clearLoadingMessage();
579         offScrImage = owner.createImage(owner.appWidth, owner.appHeight);
580         offScrGC = offScrImage.getGraphics();
581         offScrGC.setColor(Color.lightGray);
582             owner.loaded = true;
583         error = false;
584     } catch (Exception JavaDoc e) {
585         error = true;
586         e.printStackTrace();
587     }
588     }
589
590     /**
591      * Fetch an image and wait for it to come in. Used to enforce a load
592      * order for background and startup images.
593      */

594     Image fetchImageAndWait(URL JavaDoc imageURL, int trackerClass)
595                               throws InterruptedException JavaDoc {
596     Image image = owner.getImage(imageURL);
597     tracker.addImage(image, trackerClass);
598     tracker.waitForID(trackerClass);
599     return image;
600     }
601
602     /**
603      * Stuff a range of image names into a List
604      * @return a List of image URLs.
605      */

606     void prepareImageRange(int startImage, int endImage, String JavaDoc pattern)
607     throws MalformedURLException JavaDoc {
608     frames = new ArrayList JavaDoc(Math.abs(endImage - startImage) + 1);
609     if (pattern == null)
610         pattern = "T%N.gif";
611     if (startImage > endImage) {
612         for (int i = startImage; i >= endImage; i--) {
613                 AnimationFrame frame = new AnimationFrame();
614         frames.add(frame);
615                 frame.duration = globalPause;
616                 frame.imageLocation = new URL JavaDoc(imageSource,
617                                               doSubst(pattern, i+""));
618         }
619     } else {
620         for (int i = startImage; i <= endImage; i++) {
621                 AnimationFrame frame = new AnimationFrame();
622         frames.add(frame);
623                 frame.duration = globalPause;
624                 frame.imageLocation = new URL JavaDoc(imageSource,
625                                               doSubst(pattern, i+""));
626         }
627     }
628     }
629
630     /**
631      * Parse the SOUNDS parameter. It looks like
632      * train.au||hello.au||stop.au, etc., where each item refers to a
633      * source image. Empty items mean that the corresponding image
634      * has no associated sound.
635      */

636     void parseSounds(String JavaDoc attr) throws MalformedURLException JavaDoc {
637     int frameIndex = 0;
638     int numFrames = frames.size();
639     for (int i = 0; (i < attr.length()) && (frameIndex < numFrames); ) {
640         int next = attr.indexOf('|', i);
641         if (next == -1) next = attr.length();
642         String JavaDoc sound = attr.substring(i, next);
643         if (sound.length() != 0) {
644                 AnimationFrame frame = (AnimationFrame) frames.get(frameIndex);
645         frame.soundLocation = new URL JavaDoc(soundSource, sound);
646         }
647         i = next + 1;
648         frameIndex++;
649         }
650     }
651
652     /**
653      * Parse the IMAGES parameter. It looks like
654      * 1|2|3|4|5, etc., where each number (item) names a source image.
655      */

656     void parseImages(String JavaDoc attr, String JavaDoc pattern)
657                            throws MalformedURLException JavaDoc {
658         frames = new ArrayList JavaDoc();
659     if (pattern == null)
660         pattern = "T%N.gif";
661     for (int i = 0; i < attr.length(); ) {
662         int next = attr.indexOf('|', i);
663         if (next == -1) next = attr.length();
664         String JavaDoc file = attr.substring(i, next);
665             AnimationFrame frame = new AnimationFrame();
666             frames.add(frame);
667             frame.imageLocation = new URL JavaDoc(imageSource, doSubst(pattern, file));
668             frame.duration = globalPause;
669         i = next + 1;
670     }
671     }
672
673     /**
674      * Parse the PAUSES parameter. It looks like
675      * 1000|500|||750, etc., where each item corresponds to a
676      * source image. Empty items mean that the corresponding image
677      * has no special duration, and should use the global one.
678      *
679      * @return a Hashtable of Integer pauses keyed to Integer
680      * frame numbers.
681      */

682     void parseDurations(String JavaDoc attr) {
683     int imageNum = 0;
684     int numImages = frames.size();
685     for (int i = 0; (i < attr.length()) && (imageNum < numImages); ) {
686         int next = attr.indexOf('|', i);
687         if (next == -1) next = attr.length();
688             AnimationFrame aFrame = (AnimationFrame) frames.get(imageNum);
689         if (i != next) {
690         int duration = Integer.parseInt(attr.substring(i, next));
691                 aFrame.duration = duration;
692         }
693         i = next + 1;
694         imageNum++;
695     }
696     }
697
698     /**
699      * Parse a String of form xxx@yyy and return a Point.
700      */

701     Point parsePoint(String JavaDoc s) throws ParseException {
702     int atPos = s.indexOf('@');
703     if (atPos == -1) throw new ParseException("Illegal position: "+s);
704     return new Point(Integer.parseInt(s.substring(0, atPos)),
705              Integer.parseInt(s.substring(atPos + 1)));
706     }
707
708     /**
709      * Parse the POSITIONS parameter. It looks like
710      * 10@30|11@31|||12@20, etc., where each item is an X@Y coordinate
711      * corresponding to a source image. Empty items mean that the
712      * corresponding image has the same position as the preceding one.
713      *
714      * @return a Hashtable of Points keyed to Integer frame numbers.
715      */

716     void parsePositions(String JavaDoc param)
717     throws ParseException {
718     int imageNum = 0;
719     int numImages = frames.size();
720     for (int i = 0; (i < param.length()) && (imageNum < numImages); ) {
721         int next = param.indexOf('|', i);
722         if (next == -1)
723                 next = param.length();
724         if (i != next) {
725                 AnimationFrame frame = (AnimationFrame) frames.get(imageNum);
726                 frame.position = parsePoint(param.substring(i, next));
727             }
728         i = next + 1;
729         imageNum++;
730     }
731     }
732
733     /**
734      * Substitute an integer some number of times in a string, subject to
735      * parameter strings embedded in the string.
736      * Parameter strings:
737      * %N - substitute the integer as is, with no padding.
738      * %<digit>, for example %5 - substitute the integer left-padded with
739      * zeros to <digits> digits wide.
740      * %% - substitute a '%' here.
741      * @param inStr the String to substitute within
742      * @param theInt the int to substitute, as a String.
743      */

744     String JavaDoc doSubst(String JavaDoc inStr, String JavaDoc theInt) {
745     String JavaDoc padStr = "0000000000";
746     int length = inStr.length();
747     StringBuffer JavaDoc result = new StringBuffer JavaDoc(length);
748     
749     for (int i = 0; i < length;) {
750         char ch = inStr.charAt(i);
751         if (ch == '%') {
752         i++;
753         if (i == length) {
754             result.append(ch);
755         } else {
756             ch = inStr.charAt(i);
757             if (ch == 'N' || ch == 'n') {
758             // just stick in the number, unmolested
759
result.append(theInt);
760             i++;
761             } else {
762             int pad;
763             if ((pad = Character.digit(ch, 10)) != -1) {
764                 // we've got a width value
765
String JavaDoc numStr = theInt;
766                 String JavaDoc scr = padStr+numStr;
767                 result.append(scr.substring(scr.length() - pad));
768                 i++;
769             } else {
770                 result.append(ch);
771                 i++;
772             }
773             }
774         }
775         } else {
776         result.append(ch);
777         i++;
778         }
779     }
780     return result.toString();
781     }
782
783     void startPlaying() {
784     if (soundTrack != null) {
785         soundTrack.loop();
786         }
787     }
788
789     void stopPlaying() {
790     if (soundTrack != null) {
791         soundTrack.stop();
792         }
793     }
794
795     public void paint(Graphics g) {
796         int xPos = 0;
797         int yPos = 0;
798         if ((frames.size() > 0) && tracker.checkID(ANIMATION_ID) &&
799                                                           (offScrGC != null)) {
800             AnimationFrame frame = (AnimationFrame) frames.get(currentFrame);
801             Image image = frame.image;
802             if (backgroundImage == null) {
803                 offScrGC.clearRect(0, 0, owner.appWidth, owner.appHeight);
804             }
805             else
806                 offScrGC.drawImage(backgroundImage, 0, 0, owner);
807             Point pos = null;
808             if (frame.position != null) {
809                 xPos = frame.position.x;
810                 yPos = frame.position.y;
811             }
812             if (backgroundColor != null) {
813                 offScrGC.setColor(backgroundColor);
814                 offScrGC.fillRect(0, 0, owner.appWidth, owner.appHeight);
815                 offScrGC.drawImage(image, xPos, yPos, backgroundColor, owner);
816             } else {
817                 offScrGC.drawImage(image, xPos, yPos, owner);
818             }
819             if (offScrImage != null)
820                 g.drawImage(offScrImage, 0, 0, owner);
821         }
822     }
823 }
824
825 /**
826  * Instances of this class represent a single frame of an animation
827  * There can be an image, sound, and position associated with each frame
828  */

829 class AnimationFrame extends Object JavaDoc {
830     static final String JavaDoc imageLabel = "image";
831     static final String JavaDoc soundLabel = "sound";
832
833     URL JavaDoc imageLocation = null; // Directory or URL of this frames image
834
URL JavaDoc soundLocation = null; // Directory or URL of this frames sound
835
int duration; // Duration time for this frame in milliseconds
836
AudioClip JavaDoc sound; // Sound associated with this frame object
837
Image image; // Image associated with this frame
838
Point position; // Position of this frame
839

840 }
841
842 /**
843  * ParseException: signals a parameter parsing problem.
844  */

845 class ParseException extends Exception JavaDoc {
846     ParseException(String JavaDoc s) {
847     super(s);
848     }
849 }
850
851 /**
852  * DescriptionFrame: implements a pop-up "About" box.
853  */

854 class DescriptionFrame extends Frame implements ActionListener {
855     static final int rows = 27;
856     static final int cols = 70;
857     TextArea info;
858     Button cancel;
859
860     DescriptionFrame() {
861     super("Animator v1.10");
862     add("Center", info = new TextArea(rows, cols));
863     info.setEditable(false);
864     info.setBackground(Color.white);
865     Panel buttons = new Panel();
866     add("South", buttons);
867     buttons.add(cancel = new Button("Cancel"));
868     cancel.addActionListener(this);
869     pack();
870     }
871
872     public void show() {
873     info.select(0,0);
874     super.show();
875     }
876
877     void tell(String JavaDoc s) {
878     info.append(s);
879     }
880
881     public void actionPerformed(ActionEvent e) {
882     setVisible(false);
883     }
884 }
885
886
Popular Tags