package toy.image; import java.applet.*; import java.awt.*; import java.awt.image.*; import java.net.*; import toy.*; /** * ToyImageManager is a class that manages the images the jpeg and gif files * which Visual X-TOY uses. It loads the images via URL (in the X-TOY Applet) * or from the filesystem (in the X-TOY Application). It also resizes Sim mode * graphics and keeps old versions of resized graphics (to save time). Finally, * it monitors the download progress of the images for the Splash screen to * display. * * @author Brian Tsang * @version 1.0 */ public class ToyImageManager implements ImageObserver { /** * The imageIndex of the background for the splash screen. * @see #getImage(int) */ public static final int SPLASH_BACKGROUND = 0; /** * The imageIndex of the icon for the frame. * @see #getImage(int) */ public static final int FRAME_ICON = 2; /** * The imageIndex of the animation image (this is actually a big image * that contains all the different animation frames in a * ANIMATION_COLUMNS x * (ANIMATION_FRAMES / ANIMATION_COLUMNS) matrix. * @see #getImage(int) * @see #ANIMATION_COLUMNS * @see #ANIMATION_FRAMES */ public static final int POPUP_ANIMATION = 3; /** * The width of each animation frame. * @see #POPUP_ANIMATION */ public static final int ANIMATION_WIDTH = 64; /** * The height of each animation frame. * @see #POPUP_ANIMATION */ public static final int ANIMATION_HEIGHT = 64; /** * The the number of columns in the frame matrix in the animation image. * @see #POPUP_ANIMATION */ public static final int ANIMATION_COLUMNS = 10; /** * The the number of frames in the frame matrix in the animation image. * @see #POPUP_ANIMATION */ public static final int ANIMATION_FRAMES = 60; /** * The imageIndex of the inactive, unhighlighted state of the Edit tab. * @see #getImage(int) */ public static final int FRAME_TITLE_EDIT_OFF = 10; /** * The imageIndex of the inactive, but highlighted state of the Edit tab. * @see #getImage(int) */ public static final int FRAME_TITLE_EDIT_HOVER = 11; /** * The imageIndex of the active state of the Edit tab. * @see #getImage(int) */ public static final int FRAME_TITLE_EDIT_ON = 12; /** * The imageIndex of the inactive, unhighlighted state of the Debug tab. * @see #getImage(int) */ public static final int FRAME_TITLE_DEBUG_OFF = 13; /** * The imageIndex of the inactive, but highlighted state of the Debug tab. * @see #getImage(int) */ public static final int FRAME_TITLE_DEBUG_HOVER = 14; /** * The imageIndex of the active state of the Debug tab. * @see #getImage(int) */ public static final int FRAME_TITLE_DEBUG_ON = 15; /** * The imageIndex of the inactive, unhighlighted state of the Sim tab. * @see #getImage(int) */ public static final int FRAME_TITLE_SIM_OFF = 16; /** * The imageIndex of the inactive, but highlighted state of the Sim tab. * @see #getImage(int) */ public static final int FRAME_TITLE_SIM_HOVER = 17; /** * The imageIndex of the active state of the Sim tab. * @see #getImage(int) */ public static final int FRAME_TITLE_SIM_ON = 18; /** * The lower bound of the imageIndex range which will be subject to * resizing. * @see #setSimUnit(int) * @see #SCALE_UPPER_BOUND */ public static final int SCALE_LOWER_BOUND = 20; /** * The imageIndex of the unlit state of the Load button. * @see #getImage(int) */ public static final int FRAME_SIM_LOAD_OFF = 20; /** * The imageIndex of the lit state of the Load button. * @see #getImage(int) */ public static final int FRAME_SIM_LOAD_ON = 21; /** * The imageIndex of the unlit state of the Look button. * @see #getImage(int) */ public static final int FRAME_SIM_LOOK_OFF = 22; /** * The imageIndex of the lit state of the Look button. * @see #getImage(int) */ public static final int FRAME_SIM_LOOK_ON = 23; /** * The imageIndex of the unlit state of the Reset button. * @see #getImage(int) */ public static final int FRAME_SIM_RESET_OFF = 24; /** * The imageIndex of the lit state of the Reset button. * @see #getImage(int) */ public static final int FRAME_SIM_RESET_ON = 25; /** * The imageIndex of the unlit state of the Run button. * @see #getImage(int) */ public static final int FRAME_SIM_RUN_OFF = 26; /** * The imageIndex of the lit state of the Run button. * @see #getImage(int) */ public static final int FRAME_SIM_RUN_ON = 27; /** * The imageIndex of the unlit state of the Step button. * @see #getImage(int) */ public static final int FRAME_SIM_STEP_OFF = 28; /** * The imageIndex of the lit state of the Step button. * @see #getImage(int) */ public static final int FRAME_SIM_STEP_ON = 29; /** * The imageIndex of the "ADDR" label. * @see #getImage(int) */ public static final int FRAME_SIM_ADDR = 30; /** * The imageIndex of the "DATA" label. * @see #getImage(int) */ public static final int FRAME_SIM_DATA = 31; /** * The imageIndex of the "OUTPUT" label. * @see #getImage(int) */ public static final int FRAME_SIM_OUTPUT = 32; /** * The imageIndex of the down state of the switch. * @see #getImage(int) */ public static final int FRAME_SIM_SWITCH_OFF = 33; /** * The imageIndex of the up state of the switch. * @see #getImage(int) */ public static final int FRAME_SIM_SWITCH_ON = 34; /** * The imageIndex of the unlit of the light. * @see #getImage(int) */ public static final int FRAME_SIM_LIGHT_OFF = 35; /** * The imageIndex of the lit of the light. * @see #getImage(int) */ public static final int FRAME_SIM_LIGHT_ON = 36; /** * The imageIndex of the blank LCD digit. * @see #getImage(int) * @see #FRAME_SIM_DIGIT */ public static final int FRAME_SIM_DIGIT_BLANK = 39; /** * The imageIndex of the 0 LCD digit (add n to get the imageIndex of the * nth LCD digit. * @see #getImage(int) * @see #FRAME_SIM_DIGIT_BLANK */ public static final int FRAME_SIM_DIGIT = 40; //this is an array which ranges from 0 to 15 /** * The upper bound of the imageIndex range which will be subject to * resizing. * @see #setSimUnit(int) * @see #SCALE_LOWER_BOUND */ public static final int SCALE_UPPER_BOUND = 59; /** * The size of the entire array of images. Note that not every element of * the array is used. * @see #getImage(int) */ public static final int IMAGE_CARDINALITY = 60; /** * The simUnit size which the raw images are loaded as. * @see #getImage(int) */ public static final int IMAGE_SIM_UNIT = 30; /** * The maximum simUnit size which the images will be scaled to. * @see #getImage(int) */ public static final int MAX_SIM_UNIT = 60; /** * The lower bound of the simUnit range for which the Visual X-TOY will be * prepared for. * @see #getImage(int) * @see #PREPARE_SIM_UPPER_BOUND */ private static final int PREPARE_SIM_LOWER_BOUND = 7; /** * The lower bound of the simUnit range for which the Visual X-TOY will be * prepared for. * @see #getImage(int) * @see #PREPARE_SIM_LOWER_BOUND */ private static final int PREPARE_SIM_UPPER_BOUND = 7; /** * The array of unscaled images. * @see #getImage(int) */ private Image imageArray[]; /** * The the two dimensional array of scaled images. The first dimension is * the simUnit size for which the images are scaled, and the second * dimension parallels that of imageArray. * @see #getImage(int) * @see #imageArray */ private Image scaledImageArray[][]; /** * The current scaling of the image that getImage() will return. * @see #getImage(int) * @see #setSimUnit(int) */ private int simUnit; /** * The total number of images that have been downloaded. * @see #getImage(int) * @see #setSimUnit(int) */ private int imagesDownloaded; /** * The total number of images expected to be downloaded. * @see #getImage(int) * @sse #setSimUnit(int) */ private int totalImages; /** * A buffer on which to draw the images to stimulate downloading. * @see #offscreen */ private Image offscreenImage; /** * The graphics object to the offscreenImage. * @see #offscreenImage */ private Graphics offscreen; /** * Constructs a ToyImageManager which will load its images from a URL * provided by parentApplet. * * @param parentApplet the applet from which to load the images. */ public ToyImageManager(Applet parentApplet) { URL codeBase = parentApplet.getCodeBase(); imageArray = new Image[IMAGE_CARDINALITY]; scaledImageArray = new Image[MAX_SIM_UNIT + 1][]; for (int ctr = PREPARE_SIM_LOWER_BOUND; ctr <= PREPARE_SIM_UPPER_BOUND; ctr++) scaledImageArray[ctr] = new Image[SCALE_UPPER_BOUND - SCALE_LOWER_BOUND + 1]; //get images imageArray[SPLASH_BACKGROUND] = parentApplet.getImage( codeBase, "toy/image/splashBackground.jpg"); imageArray[FRAME_ICON] = parentApplet.getImage( codeBase, "toy/image/frameIcon.gif"); imageArray[POPUP_ANIMATION] = parentApplet.getImage( codeBase, "toy/image/popupAnimation.jpg"); imageArray[FRAME_TITLE_EDIT_OFF] = parentApplet.getImage( codeBase, "toy/image/frameTitleEditOff.jpg"); imageArray[FRAME_TITLE_EDIT_HOVER] = parentApplet.getImage( codeBase, "toy/image/frameTitleEditHover.jpg"); imageArray[FRAME_TITLE_EDIT_ON] = parentApplet.getImage( codeBase, "toy/image/frameTitleEditOn.jpg"); imageArray[FRAME_TITLE_DEBUG_OFF] = parentApplet.getImage( codeBase, "toy/image/frameTitleDebugOff.jpg"); imageArray[FRAME_TITLE_DEBUG_HOVER]= parentApplet.getImage( codeBase, "toy/image/frameTitleDebugHover.jpg"); imageArray[FRAME_TITLE_DEBUG_ON] = parentApplet.getImage( codeBase, "toy/image/frameTitleDebugOn.jpg"); imageArray[FRAME_TITLE_SIM_OFF] = parentApplet.getImage( codeBase, "toy/image/frameTitleSimOff.jpg"); imageArray[FRAME_TITLE_SIM_HOVER] = parentApplet.getImage( codeBase, "toy/image/frameTitleSimHover.jpg"); imageArray[FRAME_TITLE_SIM_ON] = parentApplet.getImage( codeBase, "toy/image/frameTitleSimOn.jpg"); imageArray[FRAME_SIM_LOAD_OFF] = parentApplet.getImage( codeBase, "toy/image/frameSimLoadOff.jpg"); imageArray[FRAME_SIM_LOAD_ON] = parentApplet.getImage( codeBase, "toy/image/frameSimLoadOn.jpg"); imageArray[FRAME_SIM_LOOK_OFF] = parentApplet.getImage( codeBase, "toy/image/frameSimLookOff.jpg"); imageArray[FRAME_SIM_LOOK_ON] = parentApplet.getImage( codeBase, "toy/image/frameSimLookOn.jpg"); imageArray[FRAME_SIM_RESET_OFF] = parentApplet.getImage( codeBase, "toy/image/frameSimResetOff.jpg"); imageArray[FRAME_SIM_RESET_ON] = parentApplet.getImage( codeBase, "toy/image/frameSimResetOn.jpg"); imageArray[FRAME_SIM_RUN_OFF] = parentApplet.getImage( codeBase, "toy/image/frameSimRunOff.jpg"); imageArray[FRAME_SIM_RUN_ON] = parentApplet.getImage( codeBase, "toy/image/frameSimRunOn.jpg"); imageArray[FRAME_SIM_STEP_OFF] = parentApplet.getImage( codeBase, "toy/image/frameSimStepOff.jpg"); imageArray[FRAME_SIM_STEP_ON] = parentApplet.getImage( codeBase, "toy/image/frameSimStepOn.jpg"); imageArray[FRAME_SIM_ADDR] = parentApplet.getImage( codeBase, "toy/image/frameSimAddr.jpg"); imageArray[FRAME_SIM_DATA] = parentApplet.getImage( codeBase, "toy/image/frameSimData.jpg"); imageArray[FRAME_SIM_OUTPUT] = parentApplet.getImage( codeBase, "toy/image/frameSimOutput.jpg"); imageArray[FRAME_SIM_SWITCH_OFF] = parentApplet.getImage( codeBase, "toy/image/frameSimSwitchOff.jpg"); imageArray[FRAME_SIM_SWITCH_ON] = parentApplet.getImage( codeBase, "toy/image/frameSimSwitchOn.jpg"); imageArray[FRAME_SIM_LIGHT_OFF ] = parentApplet.getImage( codeBase, "toy/image/frameSimLightOff.jpg"); imageArray[FRAME_SIM_LIGHT_ON] = parentApplet.getImage( codeBase, "toy/image/frameSimLightOn.jpg"); imageArray[FRAME_SIM_DIGIT_BLANK] = parentApplet.getImage( codeBase, "toy/image/frameSimDigitBlank.jpg"); for (short ctr = 0; ctr < 0x10; ctr++) imageArray[FRAME_SIM_DIGIT + ctr] = parentApplet.getImage( codeBase, "toy/image/frameSimDigit" + ToyWord.convertToHexDigit(ctr) + ".jpg" ); //stimulate the download of the images by pretending to draw them offscreenImage = parentApplet.createImage(100, 100); offscreen = offscreenImage.getGraphics(); imagesDownloaded = 0; totalImages = 0; for (int ctr = 0; ctr < IMAGE_CARDINALITY; ctr++) if (imageArray[ctr] != null) { offscreen.drawImage(imageArray[ctr], 0, 0, this); totalImages++; if (ctr >= SCALE_LOWER_BOUND && ctr <= SCALE_UPPER_BOUND) totalImages += PREPARE_SIM_UPPER_BOUND - PREPARE_SIM_LOWER_BOUND + 1; } } /** * Constructs a ToyImageManager which will load its images from the * filesystem. * * @param parentWindow the window to create an offscreenImage from */ public ToyImageManager(Window parentWindow) { imageArray = new Image[IMAGE_CARDINALITY]; scaledImageArray = new Image[MAX_SIM_UNIT + 1][]; for (int ctr = PREPARE_SIM_LOWER_BOUND; ctr <= PREPARE_SIM_UPPER_BOUND; ctr++) scaledImageArray[ctr] = new Image[SCALE_UPPER_BOUND - SCALE_LOWER_BOUND + 1]; //get images imageArray[SPLASH_BACKGROUND] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("splashBackground.jpg")); imageArray[FRAME_ICON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameIcon.gif")); imageArray[POPUP_ANIMATION] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("popupAnimation.jpg")); imageArray[FRAME_TITLE_EDIT_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleEditOff.jpg")); imageArray[FRAME_TITLE_EDIT_HOVER] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleEditHover.jpg")); imageArray[FRAME_TITLE_EDIT_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleEditOn.jpg")); imageArray[FRAME_TITLE_DEBUG_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleDebugOff.jpg")); imageArray[FRAME_TITLE_DEBUG_HOVER]= Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleDebugHover.jpg")); imageArray[FRAME_TITLE_DEBUG_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleDebugOn.jpg")); imageArray[FRAME_TITLE_SIM_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleSimOff.jpg")); imageArray[FRAME_TITLE_SIM_HOVER] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleSimHover.jpg")); imageArray[FRAME_TITLE_SIM_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameTitleSimOn.jpg")); imageArray[FRAME_SIM_LOAD_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimLoadOff.jpg")); imageArray[FRAME_SIM_LOAD_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimLoadOn.jpg")); imageArray[FRAME_SIM_LOOK_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimLookOff.jpg")); imageArray[FRAME_SIM_LOOK_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimLookOn.jpg")); imageArray[FRAME_SIM_RESET_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimResetOff.jpg")); imageArray[FRAME_SIM_RESET_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimResetOn.jpg")); imageArray[FRAME_SIM_RUN_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimRunOff.jpg")); imageArray[FRAME_SIM_RUN_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimRunOn.jpg")); imageArray[FRAME_SIM_STEP_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimStepOff.jpg")); imageArray[FRAME_SIM_STEP_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimStepOn.jpg")); imageArray[FRAME_SIM_ADDR] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimAddr.jpg")); imageArray[FRAME_SIM_DATA] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimData.jpg")); imageArray[FRAME_SIM_OUTPUT] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimOutput.jpg")); imageArray[FRAME_SIM_SWITCH_OFF] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimSwitchOff.jpg")); imageArray[FRAME_SIM_SWITCH_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimSwitchOn.jpg")); imageArray[FRAME_SIM_LIGHT_OFF ] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimLightOff.jpg")); imageArray[FRAME_SIM_LIGHT_ON] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimLightOn.jpg")); imageArray[FRAME_SIM_DIGIT_BLANK] = Toolkit.getDefaultToolkit().getImage( getClass().getResource("frameSimDigitBlank.jpg")); for (short ctr = 0; ctr < 0x10; ctr++) imageArray[FRAME_SIM_DIGIT + ctr] = Toolkit.getDefaultToolkit().getImage( getClass().getResource( "frameSimDigit" + ToyWord.convertToHexDigit(ctr) + ".jpg" ) ); //stimulate the download of the images by pretending to draw them offscreenImage = parentWindow.createImage(100, 100); offscreen = offscreenImage.getGraphics(); imagesDownloaded = 0; totalImages = 0; for (int ctr = 0; ctr < IMAGE_CARDINALITY; ctr++) if (imageArray[ctr] != null) { if (!offscreen.drawImage(imageArray[ctr], 0, 0, this)) { totalImages++; if (ctr >= SCALE_LOWER_BOUND && ctr <= SCALE_UPPER_BOUND) totalImages += PREPARE_SIM_UPPER_BOUND - PREPARE_SIM_LOWER_BOUND + 1; } } } /** * Returns true iff all the images have been accounted for (downloaded, * encountered an error, or timed out). * * @return true iff all the images have been accounted for */ public boolean isReady() { return imagesDownloaded >= totalImages; } /** * Returns the percentage (to the nearest 1%) of images that have been * accounted for so far. * * @return the percentage (to the nearest 1%) of images that have been * accounted for so far. */ public int getPercentDone() { if (totalImages == 0) return 100; return (int)((100.0 * imagesDownloaded) / totalImages); } /** * Returns the unscaled version of the image at imageIndex even if a * scaled version is available. * * @return the unscaled version of the image at imageIndex. * @param imageIndex the integer corresponding to the desired image * @see #getImage(int) */ public Image getUnscaledImage(int imageIndex) { if (imageIndex < 0 || imageIndex >= IMAGE_CARDINALITY) return null; return imageArray[imageIndex]; } /** * Returns the scaled version of the image at imageIndex if available, * otherwise, returns the unscaled verion of the image. * * @return the unscaled version of the image at imageIndex. * @param imageIndex the integer corresponding to the desired image * @see #getImage(int) */ public Image getImage(int imageIndex) { if (imageIndex < 0 || imageIndex >= IMAGE_CARDINALITY) return null; if (imageIndex >= SCALE_LOWER_BOUND && imageIndex <= SCALE_UPPER_BOUND) return scaledImageArray[simUnit][imageIndex - SCALE_LOWER_BOUND]; else return imageArray[imageIndex]; } /** * Generates the rescaled images if necessary. Calls to * getImage will return an image scaled to * newSimUnit, if possible. * * @param newSimUnit the new scaling value of the simUnit. * @see #getUnscaledImage(int) */ public void setSimUnit(int newSimUnit) { if (newSimUnit > MAX_SIM_UNIT) newSimUnit = MAX_SIM_UNIT; simUnit = newSimUnit; if (scaledImageArray[simUnit] == null) { scaledImageArray[simUnit] = new Image[SCALE_UPPER_BOUND - SCALE_LOWER_BOUND + 1]; for (int ctr = SCALE_LOWER_BOUND; ctr <= SCALE_UPPER_BOUND; ctr++) if (imageArray[ctr] != null) { scaledImageArray[simUnit][ctr - SCALE_LOWER_BOUND] = imageArray[ctr].getScaledInstance( (int)(simUnit * 1.0 / IMAGE_SIM_UNIT * imageArray[ctr].getWidth(null)), (int)(simUnit * 1.0 / IMAGE_SIM_UNIT * imageArray[ctr].getHeight(null)), Image.SCALE_AREA_AVERAGING ); if (offscreen.drawImage( scaledImageArray[simUnit][ctr - SCALE_LOWER_BOUND], 0, 0, this)) imagesDownloaded++; } } } /** * Implement the ImageObserver interface (for monitoring the progress of * the image downloads). */ public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { if ((infoflags & ALLBITS) != 0 || (infoflags & ERROR) != 0 || (infoflags & ABORT) != 0) { imagesDownloaded++; int index = -1; for (int ctr = 0; index == -1 && ctr < IMAGE_CARDINALITY; ctr++) if (imageArray[ctr] == img) index = ctr; if (index >= SCALE_LOWER_BOUND && index <= SCALE_UPPER_BOUND) for (int ctr = PREPARE_SIM_LOWER_BOUND; ctr <= PREPARE_SIM_UPPER_BOUND; ctr++) { scaledImageArray[ctr][index - SCALE_LOWER_BOUND] = imageArray[index].getScaledInstance( (int)(ctr * 1.0 / IMAGE_SIM_UNIT * imageArray[index].getWidth(null)), (int)(ctr * 1.0 / IMAGE_SIM_UNIT * imageArray[index].getHeight(null)), Image.SCALE_AREA_AVERAGING ); offscreen.drawImage( scaledImageArray[ctr][index - SCALE_LOWER_BOUND], 0, 0, this ); } return false; } return true; } }