blob: 1f9fbf2c926578d5e29c82fab17d107e2b394fab [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2010 Soyatec (http://www.soyatec.com) and others.
* 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:
* Soyatec - initial API and implementation
*******************************************************************************/
package org.eclipse.xwt.vex.swt;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CLabel;
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.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
public class AnimatedImage extends CLabel {
protected InputStream imageFile;
protected boolean stop = true;
protected boolean useGIFBackground = false;
protected int horizontalAlignment = SWT.LEFT;
protected int verticalAlignment = SWT.TOP;
protected AnimationRunnable animateThread = new AnimationRunnable();
class AnimationRunnable implements Runnable {
protected ImageLoader loader;
protected Image image;
protected ImageData[] imageDataArray;
protected GC targetGC;
protected Image offScreenImage;
protected GC offScreenImageGC;
protected int imageDataIndex = 0;
protected int repeatCount;
public void run() {
if (isDisposed() || stop) {
clearStop();
return;
}
Display display = getDisplay();
Color background = getBackground();
if (loader == null) {
setText("");
loader = new ImageLoader();
imageDataArray = loader.load(imageFile);
targetGC = new GC(AnimatedImage.this);
/*
* Create an off-screen image to draw on, and fill it with the shell background.
*/
offScreenImage = new Image(display, loader.logicalScreenWidth, loader.logicalScreenHeight);
offScreenImageGC = new GC(offScreenImage);
offScreenImageGC.setBackground(background);
offScreenImageGC.fillRectangle(0, 0, loader.logicalScreenWidth, loader.logicalScreenHeight);
/*
* Create the first image and draw it on the off-screen image.
*/
imageDataIndex = 0;
ImageData imageData = imageDataArray[imageDataIndex];
if (image != null && !image.isDisposed())
image.dispose();
image = new Image(display, imageData);
offScreenImageGC.drawImage(image, 0, 0, imageData.width, imageData.height, imageData.x, imageData.y, imageData.width, imageData.height);
repeatCount = loader.repeatCount;
}
try {
/*
* Now loop through the images, creating and drawing each one on the off-screen image before drawing it on the shell.
*/
ImageData imageData = imageDataArray[imageDataIndex];
if (loader.repeatCount == 0 || repeatCount > 0) {
switch (imageData.disposalMethod) {
case SWT.DM_FILL_BACKGROUND:
/*
* Fill with the background color before drawing.
*/
Color bgColor = null;
if (useGIFBackground && loader.backgroundPixel != -1) {
bgColor = new Color(display, imageData.palette.getRGB(loader.backgroundPixel));
}
offScreenImageGC.setBackground(bgColor != null ? bgColor : background);
offScreenImageGC.fillRectangle(imageData.x, imageData.y, imageData.width, imageData.height);
if (bgColor != null)
bgColor.dispose();
break;
case SWT.DM_FILL_PREVIOUS:
/*
* Restore the previous image before drawing.
*/
offScreenImageGC.drawImage(image, 0, 0, imageData.width, imageData.height, imageData.x, imageData.y, imageData.width, imageData.height);
break;
}
imageDataIndex = (imageDataIndex + 1) % imageDataArray.length;
imageData = imageDataArray[imageDataIndex];
image.dispose();
image = new Image(display, imageData);
offScreenImageGC.drawImage(image, 0, 0, imageData.width, imageData.height, imageData.x, imageData.y, imageData.width, imageData.height);
/* Draw the off-screen image to the composite. */
Rectangle container = getBounds();
Rectangle imageBound = offScreenImage.getBounds();
int x = 0;
int y = 0;
switch (horizontalAlignment) {
case SWT.LEFT:
break;
case SWT.RIGHT:
x = (container.width - imageBound.width);
break;
case SWT.CENTER:
x = (container.width - imageBound.width) / 2;
break;
default:
throw new IllegalStateException("HorizontalAlignment " + horizontalAlignment);
}
switch (verticalAlignment) {
case SWT.TOP:
break;
case SWT.CENTER:
y = (container.height - imageBound.height) / 2;
break;
case SWT.BOTTOM:
y = (container.height - imageBound.height);
break;
default:
throw new IllegalStateException("VerticalAlignment " + verticalAlignment);
}
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
targetGC.drawImage(offScreenImage, x, y);
/*
* Sleep for the specified delay time (adding commonly-used slow-down fudge factors).
*/
{
int ms = imageData.delayTime * 10;
if (ms < 20)
ms += 30;
if (ms < 30)
ms += 10;
getDisplay().timerExec(ms, this);
}
/*
* If we have just drawn the last image, decrement the repeat count and start again.
*/
if (imageDataIndex == imageDataArray.length - 1)
repeatCount--;
} else {
clearStop();
}
} catch (SWTException ex) {
System.out.println("There was an error animating the GIF");
} finally {
}
}
protected void clearStop() {
if (offScreenImage != null && !offScreenImage.isDisposed()) {
try {
offScreenImage.dispose();
} catch (Exception e) {
}
}
if (offScreenImageGC != null && !offScreenImageGC.isDisposed()) {
try {
offScreenImageGC.dispose();
} catch (Exception e) {
}
}
if (image != null && !image.isDisposed()) {
try {
image.dispose();
} catch (Exception e) {
}
}
if (targetGC != null && !targetGC.isDisposed()) {
try {
targetGC.dispose();
} catch (Exception e) {
}
}
targetGC = null;
image = null;
offScreenImageGC = null;
offScreenImage = null;
loader = null;
imageDataArray = null;
imageDataIndex = 0;
repeatCount = 0;
stop = true;
}
};
public AnimatedImage(Composite parent, int style) {
super(parent, style);
}
public int getHorizontalAlignment() {
return horizontalAlignment;
}
public void setHorizontalAlignment(int horizontalAlignment) {
this.horizontalAlignment = horizontalAlignment;
}
public int getVerticalAlignment() {
return verticalAlignment;
}
public void setVerticalAlignment(int verticalAlignment) {
this.verticalAlignment = verticalAlignment;
}
public void setImageFile(URL imageFile) throws IOException {
if (!stop) {
throw new IllegalStateException("Animation is running");
}
this.imageFile = imageFile.openStream();
if (imageFile != null) {
start();
}
}
public void start() {
stop = false;
getDisplay().asyncExec(animateThread);
}
public void stop() {
stop = true;
}
@Override
public void dispose() {
stop = true;
super.dispose();
}
}