/******************************************************************************* * Copyright (c) 2010 Yadu. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Yadu - initial API and implementation ******************************************************************************/ package code.google.restclient.test.work; import java.io.InputStream; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.ImageLoader; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import code.google.restclient.common.RCUtil; /** * @author Yaduvendra.Singh */ public class AnimatedImage { Display display; Shell shell; boolean animate = true; Button btnTest; Image image; String imageResource; // file path in classpath ImageLoader imageLoader = new ImageLoader(); Canvas imageCanvas; GC imageCanvasGC; Color imageCanvasBGColor; Color shellBGColor; Thread animateThread; public AnimatedImage() {} public AnimatedImage(Canvas canvas, String imageResource) { imageCanvas = canvas; shell = imageCanvas.getShell(); display = shell.getDisplay(); this.imageResource = imageResource; // Create a GC for drawing, and hook the listener to dispose it. imageCanvasGC = new GC(imageCanvas); imageCanvas.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { imageCanvasGC.dispose(); } }); } public boolean isAnimate() { return animate; } public void setAnimate(boolean animate) { this.animate = animate; } public static void main(String[] args) { Display display = new Display(); AnimatedImage animatedImage = new AnimatedImage(); Shell shell = animatedImage.openShell(display); while ( !shell.isDisposed() ) { if ( !display.readAndDispatch() ) display.sleep(); } display.dispose(); } private Shell openShell(Display disp) { display = disp; shell = new Shell(display); createWidgets(); testImageDraw(); shell.addShellListener(new ShellAdapter() { @Override public void shellClosed(ShellEvent e) { releaseThread(); e.doit = true; } }); shell.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { // Clean up. dispose(); } }); shell.open(); return shell; } /** * This must be called under dispose listener of its parent shell to stop animation thread */ public void releaseThread() { animate = false; // stop any animation in progress if ( animateThread != null ) { // wait for the thread to die before disposing the shell. while ( animateThread.isAlive() ) { if ( !display.readAndDispatch() ) display.sleep(); } } } public void dispose() { if ( image != null ) image.dispose(); } private void createWidgets() { GridLayout layout = new GridLayout(); layout.numColumns = 1; shell.setLayout(layout); btnTest = new Button(shell, SWT.PUSH); btnTest.setText("Button"); addListeners(); } private void addListeners() { SelectionAdapter selAdapter = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent selEvent) { if ( selEvent.getSource().equals(btnTest) ) { animate = false; } } }; btnTest.addSelectionListener(selAdapter); } public void drawImage(final boolean useImageBGColor) { InputStream is = RCUtil.getResourceAsStream(imageResource); if ( is != null ) { // if image is readable final ImageData[] imageDataArr = imageLoader.load(is); if ( imageDataArr.length == 1 ) { imageCanvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent event) { image = new Image(display, imageLoader.data[0]); // image of first frame event.gc.drawImage(image, 0, 0); } }); imageCanvas.redraw(); } if ( imageDataArr.length > 1 ) { // animation animateThread = new Thread("Animation") { @Override public void run() { loopImage(imageDataArr, useImageBGColor); } }; animateThread.start(); } } } public void drawImage(Canvas canvas, String imageResource, final boolean useImageBGColor) { imageCanvas = canvas; imageCanvasGC = new GC(imageCanvas); InputStream is = RCUtil.getResourceAsStream(imageResource); if ( is != null ) { // if image is readable final ImageData[] imageDataArr = imageLoader.load(is); if ( imageDataArr.length == 1 ) { imageCanvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent event) { image = new Image(display, imageLoader.data[0]); // image of first frame event.gc.drawImage(image, 0, 0); } }); imageCanvas.redraw(); } if ( imageDataArr.length > 1 ) { // animation animateThread = new Thread("Animation") { @Override public void run() { loopImage(imageDataArr, useImageBGColor); } }; animateThread.start(); } } } private void loopImage(ImageData[] imageDataArr, boolean useImageBGColor) { int imageDataIndex = 0; ImageData imageFrame = imageDataArr[imageDataIndex]; image = new Image(display, imageFrame); // Create an off-screen image to draw on, and a GC to draw with. Both are disposed after the animation. Image offScreenImage = new Image(display, imageLoader.logicalScreenWidth, imageLoader.logicalScreenHeight); GC offScreenImageGC = new GC(offScreenImage); try { // Use syncExec to get the background color of the imageCanvas and shell. display.syncExec(new Runnable() { public void run() { imageCanvasBGColor = imageCanvas.getBackground(); shellBGColor = shell.getBackground(); } }); // Fill the off-screen image with the background color of the canvas. offScreenImageGC.setBackground(imageCanvasBGColor); offScreenImageGC.fillRectangle(0, 0, imageLoader.logicalScreenWidth, imageLoader.logicalScreenHeight); // Draw the current image onto the off-screen image. offScreenImageGC.drawImage(image, 0, 0, imageFrame.width, imageFrame.height, imageFrame.x, imageFrame.y, imageFrame.width, imageFrame.height); int repeatCount = imageLoader.repeatCount; while ( animate && (imageLoader.repeatCount == 0 || repeatCount > 0) ) { switch ( imageFrame.disposalMethod ) { case SWT.DM_FILL_BACKGROUND: // Fill with the background color before drawing. Color bgColor = null; if ( useImageBGColor && imageLoader.backgroundPixel != -1 ) { bgColor = new Color(display, imageFrame.palette.getRGB(imageLoader.backgroundPixel)); } offScreenImageGC.setBackground(bgColor != null ? bgColor : shellBGColor); offScreenImageGC.fillRectangle(imageFrame.x, imageFrame.y, imageFrame.width, imageFrame.height); if ( bgColor != null ) bgColor.dispose(); break; case SWT.DM_FILL_PREVIOUS: // Restore the previous image before drawing. offScreenImageGC.drawImage(image, 0, 0, imageFrame.width, imageFrame.height, imageFrame.x, imageFrame.y, imageFrame.width, imageFrame.height); break; } // Get the next image data. imageDataIndex = (imageDataIndex + 1) % imageDataArr.length; imageFrame = imageDataArr[imageDataIndex]; image.dispose(); image = new Image(display, imageFrame); // Draw the new image data. offScreenImageGC.drawImage(image, 0, 0, imageFrame.width, imageFrame.height, imageFrame.x, imageFrame.y, imageFrame.width, imageFrame.height); // Draw the off-screen image to the screen. imageCanvasGC.drawImage(offScreenImage, 0, 0); // Sleep for the specified delay time before drawing again. try { Thread.sleep(visibleDelay(imageFrame.delayTime * 10)); } catch ( InterruptedException e ) {} // If we have just drawn the last image in the set, // then decrement the repeat count. if ( imageDataIndex == imageDataArr.length - 1 ) repeatCount--; } } finally { offScreenImage.dispose(); offScreenImageGC.dispose(); } } /* * Return the specified number of milliseconds. * If the specified number of milliseconds is too small * to see a visual change, then return a higher number. */ static int visibleDelay(int ms) { if ( ms < 20 ) return ms + 30; if ( ms < 30 ) return ms + 10; return ms; } private void testImageDraw() { Canvas canvas = new Canvas(shell, SWT.NONE); GridData data = new GridData(); data.horizontalAlignment = SWT.FILL; data.horizontalSpan = 1; data.grabExcessHorizontalSpace = true; canvas.setLayoutData(data); drawImage(canvas, "icons/loader.gif", false); } }