home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / VCSAMPL.BIN / ImageMap.java < prev    next >
Text File  |  1996-12-06  |  12KB  |  454 lines

  1. /*
  2.  * @(#)ImageMap.java    1.8 96/12/06
  3.  *
  4.  * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
  7.  * modify and redistribute this software in source and binary code form,
  8.  * provided that i) this copyright notice and license appear on all copies of
  9.  * the software; and ii) Licensee does not utilize the software in a manner
  10.  * which is disparaging to Sun.
  11.  *
  12.  * This software is provided "AS IS," without a warranty of any kind. ALL
  13.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  14.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  15.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  16.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  17.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  18.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  19.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  20.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  21.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  22.  * POSSIBILITY OF SUCH DAMAGES.
  23.  *
  24.  * This software is not designed or intended for use in on-line control of
  25.  * aircraft, air traffic, aircraft navigation or aircraft communications; or in
  26.  * the design, construction, operation or maintenance of any nuclear
  27.  * facility. Licensee represents and warrants that it will not use or
  28.  * redistribute the Software for such purposes.
  29.  */
  30.  
  31. import java.applet.Applet;
  32. import java.awt.Image;
  33. import java.awt.Graphics;
  34. import java.awt.Rectangle;
  35. import java.awt.MediaTracker;
  36. import java.util.StringTokenizer;
  37. import java.util.Vector;
  38. import java.util.Hashtable;
  39. import java.net.URL;
  40. import java.awt.image.ImageProducer;
  41. import java.awt.image.ImageFilter;
  42. import java.awt.image.CropImageFilter;
  43. import java.awt.image.FilteredImageSource;
  44. import java.net.MalformedURLException;
  45.  
  46. /**
  47.  * An extensible ImageMap applet class.
  48.  * The active areas on the image are controlled by ImageArea classes
  49.  * that can be dynamically loaded over the net.
  50.  *
  51.  * @author     Jim Graham
  52.  * @version     1.8, 12/06/96
  53.  */
  54. public class ImageMap extends Applet implements Runnable {
  55.     /**
  56.      * The unhighlighted image being mapped.
  57.      */
  58.     Image baseImage;
  59.  
  60.     /**
  61.      * The list of image area handling objects;
  62.      */
  63.     ImageMapArea areas[];
  64.  
  65.     /**
  66.      * The primary highlight mode to be used.
  67.      */
  68.     static final int BRIGHTER = 0;
  69.     static final int DARKER = 1;
  70.  
  71.     int hlmode = BRIGHTER;
  72.  
  73.     /**
  74.      * The percentage of highlight to apply for the primary highlight mode.
  75.      */
  76.     int hlpercent = 50;
  77.  
  78.     /**
  79.      * The MediaTracker for loading and constructing the various images.
  80.      */
  81.     MediaTracker tracker;
  82.  
  83.     /**
  84.      * Get a rectangular region of the baseImage highlighted according to
  85.      * the primary highlight specification.
  86.      */
  87.     Image getHighlight(int x, int y, int w, int h) {
  88.     return getHighlight(x, y, w, h, hlmode, hlpercent);
  89.     }
  90.  
  91.     /**
  92.      * Get a rectangular region of the baseImage with a specific highlight.
  93.      */
  94.     Image getHighlight(int x, int y, int w, int h, int mode, int percent) {
  95.     return getHighlight(x, y, w, h, new HighlightFilter(mode == BRIGHTER,
  96.                                 percent));
  97.     }
  98.  
  99.     /**
  100.      * Get a rectangular region of the baseImage modified by an image filter.
  101.      */
  102.     Image getHighlight(int x, int y, int w, int h, ImageFilter filter) {
  103.     ImageFilter cropfilter = new CropImageFilter(x, y, w, h);
  104.     ImageProducer prod = new FilteredImageSource(baseImage.getSource(),
  105.                              cropfilter);
  106.     return makeImage(prod, filter, 0);
  107.     }
  108.  
  109.     /**
  110.      * Make a filtered image based on another image.
  111.      */
  112.     Image makeImage(Image orig, ImageFilter filter) {
  113.     return makeImage(orig.getSource(), filter);
  114.     }
  115.  
  116.     /**
  117.      * Make a filtered image based on another ImageProducer.
  118.      */
  119.     Image makeImage(ImageProducer prod, ImageFilter filter) {
  120.     return makeImage(prod, filter,
  121.              (prod == baseImage.getSource()) ? 1 : 0);
  122.     }
  123.  
  124.     /**
  125.      * Make a filtered image based on another ImageProducer.
  126.      * Add it to the media tracker using the indicated ID.
  127.      */
  128.     Image makeImage(ImageProducer prod, ImageFilter filter, int ID) {
  129.     Image filtered = createImage(new FilteredImageSource(prod, filter));
  130.     tracker.addImage(filtered, ID);
  131.     return filtered;
  132.     }
  133.  
  134.     /**
  135.      * Add an image to the list of images to be tracked.
  136.      */
  137.     void addImage(Image img) {
  138.     tracker.addImage(img, 1);
  139.     }
  140.  
  141.     /**
  142.      * Parse a string representing the desired highlight to be applied.
  143.      */
  144.     void parseHighlight(String s) {
  145.     if (s == null) {
  146.         return;
  147.     }
  148.     if (s.startsWith("brighter")) {
  149.         hlmode = BRIGHTER;
  150.         if (s.length() > "brighter".length()) {
  151.         hlpercent = Integer.parseInt(s.substring("brighter".length()));
  152.         }
  153.     } else if (s.startsWith("darker")) {
  154.         hlmode = DARKER;
  155.         if (s.length() > "darker".length()) {
  156.         hlpercent = Integer.parseInt(s.substring("darker".length()));
  157.         }
  158.     }
  159.     }
  160.  
  161.     /**
  162.      * Initialize the applet. Get attributes.
  163.      *
  164.      * Initialize the ImageAreas.
  165.      * Each ImageArea is a subclass of the class ImageArea, and is
  166.      * specified with an attribute of the form:
  167.      *         areaN=ImageAreaClassName,arguments...
  168.      * The ImageAreaClassName is parsed off and a new instance of that
  169.      * class is created.  The initializer for that class is passed a
  170.      * reference to the applet and the remainder of the attribute
  171.      * string, from which the class should retrieve any information it
  172.      * needs about the area it controls and the actions it needs to
  173.      * take within that area.
  174.      */
  175.     public void init() {
  176.     String s;
  177.  
  178.     tracker = new MediaTracker(this);
  179.     parseHighlight(getParameter("highlight"));
  180.     introTune = getParameter("startsound");
  181.     baseImage = getImage(getDocumentBase(), getParameter("img"));
  182.     Vector areaVec = new Vector();
  183.     int num = 1;
  184.     while (true) {
  185.         ImageMapArea newArea;
  186.         s = getParameter("area"+num);
  187.         if (s == null) {
  188.         // Try rect for backwards compatibility.
  189.         s = getParameter("rect"+num);
  190.         if (s == null) {
  191.             break;
  192.         }
  193.         try {
  194.             newArea = new HighlightArea();
  195.             newArea.init(this, s);
  196.             areaVec.addElement(newArea);
  197.             String url = getParameter("href"+num);
  198.             if (url != null) {
  199.             s += "," + url;
  200.             newArea = new LinkArea();
  201.             newArea.init(this, s);
  202.             areaVec.addElement(newArea);
  203.             }
  204.         } catch (Exception e) {
  205.             System.out.println("error processing: "+s);
  206.             e.printStackTrace();
  207.             break;
  208.         }
  209.         } else {
  210.         try {
  211.             int classend = s.indexOf(",");
  212.             String name = s.substring(0, classend);
  213.             newArea = (ImageMapArea) Class.forName(name).newInstance();
  214.             s = s.substring(classend+1);
  215.             newArea.init(this, s);
  216.             areaVec.addElement(newArea);
  217.         } catch (Exception e) {
  218.             System.out.println("error processing: "+s);
  219.             e.printStackTrace();
  220.             break;
  221.         }
  222.         }
  223.         num++;
  224.     }
  225.     areas = new ImageMapArea[areaVec.size()];
  226.     areaVec.copyInto(areas);
  227.     checkSize();
  228.     }
  229.  
  230.     Thread aniThread = null;
  231.     String introTune = null;
  232.  
  233.     public void start() {
  234.     if (introTune != null)
  235.         try {
  236.         play(new URL(getDocumentBase(), introTune));
  237.         } catch (MalformedURLException e) {}
  238.     if (aniThread == null) {
  239.             aniThread = new Thread(this);
  240.             aniThread.setName("ImageMap Animator");
  241.             aniThread.start();
  242.     }
  243.     }
  244.  
  245.     public void run() {
  246.     Thread me = Thread.currentThread();
  247.     tracker.checkAll(true);
  248.     for (int i = areas.length; --i >= 0; ) {
  249.         areas[i].getMedia();
  250.     }
  251.     me.setPriority(Thread.MIN_PRIORITY);
  252.     while (aniThread == me) {
  253.         boolean animating = false;
  254.         for (int i = areas.length; --i >= 0; ) {
  255.         animating = areas[i].animate() || animating;
  256.         }
  257.         try {
  258.         synchronized(this) {
  259.             wait(animating ? 100 : 0);
  260.         }
  261.         } catch (InterruptedException e) {
  262.         break;
  263.         }
  264.     }
  265.     }
  266.  
  267.     public synchronized void startAnimation() {
  268.     notify();
  269.     }
  270.  
  271.     public synchronized void stop() {
  272.     aniThread = null;
  273.     notify();
  274.     for (int i = 0; i < areas.length; i++) {
  275.         areas[i].exit();
  276.     }
  277.     }
  278.  
  279.     /**
  280.      * Check the size of this applet while the image is being loaded.
  281.      */
  282.     void checkSize() {
  283.     int w = baseImage.getWidth(this);
  284.     int h = baseImage.getHeight(this);
  285.     if (w > 0 && h > 0) {
  286.         resize(w, h);
  287.         synchronized(this) {
  288.         fullrepaint = true;
  289.         }
  290.         repaint(0, 0, w, h);
  291.     }
  292.     }
  293.  
  294.     private boolean fullrepaint = false;
  295.     private final static long UPDATERATE = 100;
  296.  
  297.     /**
  298.      * Handle updates from images being loaded.
  299.      */
  300.     public boolean imageUpdate(Image img, int infoflags,
  301.                    int x, int y, int width, int height) {
  302.     if ((infoflags & (WIDTH | HEIGHT)) != 0) {
  303.         checkSize();
  304.     }
  305.     if ((infoflags & (SOMEBITS | FRAMEBITS | ALLBITS)) != 0) {
  306.         synchronized(this) {
  307.         fullrepaint = true;
  308.         }
  309.         repaint(((infoflags & (FRAMEBITS | ALLBITS)) != 0)
  310.             ? 0 : UPDATERATE,
  311.             x, y, width, height);
  312.     }
  313.     return (infoflags & (ALLBITS | ERROR)) == 0;
  314.     }
  315.  
  316.     /**
  317.      * Paint the image and all active highlights.
  318.      */
  319.     public void paint(Graphics g) {
  320.     synchronized(this) {
  321.         fullrepaint = false;
  322.     }
  323.     if (baseImage == null) {
  324.         return;
  325.     }
  326.     g.drawImage(baseImage, 0, 0, this);
  327.     if (areas != null) {
  328.         for (int i = areas.length; --i >= 0; ) {
  329.         areas[i].highlight(g);
  330.         }
  331.     }
  332.     }
  333.  
  334.     /**
  335.      * Update the active highlights on the image.
  336.      */
  337.     public void update(Graphics g) {
  338.     boolean full;
  339.     synchronized(this) {
  340.         full = fullrepaint;
  341.     }
  342.     if (full) {
  343.         paint(g);
  344.         return;
  345.     }
  346.     if (baseImage == null) {
  347.         return;
  348.     }
  349.     g.drawImage(baseImage, 0, 0, this);
  350.     if (areas == null) {
  351.         return;
  352.     }
  353.     // First unhighlight all of the deactivated areas
  354.     for (int i = areas.length; --i >= 0; ) {
  355.         areas[i].highlight(g);
  356.     }
  357.     }
  358.  
  359.     /**
  360.      * Make sure that no ImageAreas are highlighted.
  361.      */
  362.     public boolean mouseExit(java.awt.Event evt, int x, int y) {
  363.     for (int i = 0; i < areas.length; i++) {
  364.         areas[i].checkExit();
  365.     }
  366.  
  367.     return true;
  368.     }
  369.  
  370.     /**
  371.      * Find the ImageAreas that the mouse is in.
  372.      */
  373.     public boolean mouseMove(java.awt.Event evt, int x, int y) {
  374.     boolean eaten = false;
  375.  
  376.     for (int i = 0; i < areas.length; i++) {
  377.         if (!eaten && areas[i].inside(x, y)) {
  378.         eaten = areas[i].checkEnter(x, y);
  379.         } else {
  380.         areas[i].checkExit();
  381.         }
  382.     }
  383.  
  384.     return true;
  385.     }
  386.  
  387.     int pressX;
  388.     int pressY;
  389.  
  390.     /**
  391.      * Inform all active ImageAreas of a mouse press.
  392.      */
  393.     public boolean mouseDown(java.awt.Event evt, int x, int y) {
  394.     pressX = x;
  395.     pressY = y;
  396.  
  397.     for (int i = 0; i < areas.length; i++) {
  398.         if (areas[i].inside(x, y)) {
  399.         if (areas[i].press(x, y)) {
  400.             break;
  401.         }
  402.         }
  403.     }
  404.  
  405.     return true;
  406.     }
  407.  
  408.     /**
  409.      * Inform all active ImageAreas of a mouse release.
  410.      * Only those areas that were inside the original mouseDown()
  411.      * are informed of the mouseUp.
  412.      */
  413.     public boolean mouseUp(java.awt.Event evt, int x, int y) {
  414.     for (int i = 0; i < areas.length; i++) {
  415.         if (areas[i].inside(pressX, pressY)) {
  416.         if (areas[i].lift(x, y)) {
  417.             break;
  418.         }
  419.         }
  420.     }
  421.  
  422.     return true;
  423.     }
  424.  
  425.     /**
  426.      * Inform all active ImageAreas of a mouse drag.
  427.      * Only those areas that were inside the original mouseDown()
  428.      * are informed of the mouseUp.
  429.      */
  430.     public boolean mouseDrag(java.awt.Event evt, int x, int y) {
  431.     mouseMove(evt, x, y);
  432.     for (int i = 0; i < areas.length; i++) {
  433.         if (areas[i].inside(pressX, pressY)) {
  434.         if (areas[i].drag(x, y)) {
  435.             break;
  436.         }
  437.         }
  438.     }
  439.  
  440.     return true;
  441.     }
  442.  
  443.     /**
  444.      * Scan all areas looking for the topmost status string.
  445.      */
  446.     public void newStatus() {
  447.     String msg = null;
  448.     for (int i = 0; i < areas.length; i++) {
  449.         msg = areas[i].getStatus(msg);
  450.     }
  451.     showStatus(msg);
  452.     }
  453. }
  454.