/*
* Syncany, www.syncany.org
* Copyright (C) 2011-2015 Philipp C. Heckel <philipp.heckel@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.syncany.gui.history;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
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.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
/**
* This composite can display either an animated GIF,
* or a still image.
*
* <p>Using the {@link #setImage(Image) setImage()} method, a still
* PNG/GIF/JPEG image can be displayed. Using
* {@link #setAnimatedImage(String, int) setAnimatedImage()}, an animated
* GIF image can be displayed.
*
* @author Philipp C. Heckel <philipp.heckel@gmail.com>
*/
public class ImageComposite extends Composite {
public ImageComposite(Composite composite, int style) {
super(composite, style);
GridLayout mainCompositeGridLayout = new GridLayout(1, false);
mainCompositeGridLayout.marginTop = 0;
mainCompositeGridLayout.marginLeft = 0;
mainCompositeGridLayout.marginRight = 0;
mainCompositeGridLayout.horizontalSpacing = 0;
mainCompositeGridLayout.verticalSpacing = 0;
mainCompositeGridLayout.marginHeight = 0;
mainCompositeGridLayout.marginWidth = 0;
setLayout(mainCompositeGridLayout);
setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
}
/**
* Set and display a still image on the composite.
*
* @param image Image to display
*/
public void setImage(Image image) {
disposeControls();
Label imageLabel = new Label(this, SWT.NONE);
imageLabel.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));
imageLabel.setImage(image);
layout();
}
/**
* Set and display an animated GIF image on the composite.
* The animation start immediately and will run at the given frame rate.
*
* @param resourceStr Resource identifier for the GIF image to play
* @param frameRate Frame rate / speed at which to play the image (in ms / image; less is faster)
*/
public void setAnimatedImage(String resourceStr, int frameRate) {
disposeControls();
AnimatedGifComposite animatedGifComposite = new AnimatedGifComposite(this, SWT.NONE, resourceStr, frameRate);
animatedGifComposite.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
layout();
}
private void disposeControls() {
for (Control control : getChildren()) {
control.dispose();
}
}
@Override
public void dispose() {
disposeControls();
}
private class AnimatedGifComposite extends Composite {
private String resourceStr;
private int frameRate;
private Timer imageTimer;
private ImageLoader loader;
private Image image;
private int imageNumber;
private Canvas canvas;
private GC gc;
public AnimatedGifComposite(Composite composite, int style, String resourceStr, int frameRate) {
super(composite, style);
this.resourceStr = resourceStr;
this.frameRate = frameRate;
this.setBackgroundImage(null);
this.setBackgroundMode(SWT.INHERIT_DEFAULT);
this.createContents();
}
private void createContents() {
createCanvas();
createAndStartImageTimer();
}
private void createCanvas() {
loader = new ImageLoader();
loader.load(ImageComposite.class.getResourceAsStream(resourceStr));
canvas = new Canvas(this, SWT.NONE);
image = new Image(Display.getDefault(), loader.data[0]);
gc = new GC(image);
canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
paintImage(event);
}
});
canvas.setSize(image.getBounds().width, image.getBounds().height);
}
private void paintImage(PaintEvent event) {
int posX = (canvas.getSize().x - image.getBounds().width) / 2;
int posY = (canvas.getSize().y - image.getBounds().height) / 2;
event.gc.drawImage(image, posX, posY);
}
private void createAndStartImageTimer() {
imageTimer = new Timer();
imageTimer.schedule(new TimerTask() {
@Override
public void run() {
nextImage();
}
}, 0, frameRate);
}
private void nextImage() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
try {
synchronized(ImageComposite.this) {
imageNumber = (imageNumber == loader.data.length - 1) ? 0 : imageNumber + 1;
ImageData nextFrameData = loader.data[imageNumber];
Image frameImage = new Image(Display.getDefault(), nextFrameData);
if (!gc.isDisposed()) {
gc.drawImage(frameImage, nextFrameData.x, nextFrameData.y);
}
if (!canvas.isDisposed()) {
canvas.redraw();
}
frameImage.dispose();
}
}
catch (Exception e) {
// Might be disposed. We don't care, because another image
// is in the process of being initialized.
}
}
});
}
@Override
public void dispose() {
synchronized(this) {
imageTimer.cancel();
super.dispose();
}
}
}
}