package com.yoursway.swt.animations;
import java.lang.Thread.State;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;
import com.yoursway.utils.annotations.CallFromAnyThread_NonReentrant;
public class SizeAndAlphaAnimation {
private SizeAndAlphaAnimationApplier updater;
private boolean disposed = false;
private volatile int targetWidth = 0;
private volatile int targetHeight = 0;
private volatile int targetAlpha = 0;
private volatile boolean instantWidth = false;
private volatile int width = 0;
private volatile int height = 0;
private volatile int alpha = 0;
private int xDelay = 0;
private int yDelay = 0;
private static final int d = 2;
private static final int delay = 10;
private static final Collection<SizeAndAlphaAnimation> animations = new ConcurrentLinkedQueue<SizeAndAlphaAnimation>();
private static final Thread thread = new Thread(SizeAndAlphaAnimation.class.getSimpleName()) {
@Override
public void run() {
try {
while (true) {
Iterator<SizeAndAlphaAnimation> it = animations.iterator();
while (it.hasNext()) {
SizeAndAlphaAnimation animation = it.next();
if (animation.isDisposed()) {
animation.updater = null;
it.remove();
continue;
}
animation.updateSize();
animation.updateAlpha();
}
sleep(10);
}
} catch (InterruptedException e) {
interrupted();
}
}
};
public void start(final SizeAndAlphaAnimationApplier updater) {
this.updater = updater;
animations.add(this);
if (thread.getState() == State.NEW) {
thread.setDaemon(true);
thread.start();
}
}
private void updateSize() {
if (!updater.visible()) {
width = targetWidth;
height = targetHeight;
updater.updateSize(width, height);
return;
}
int x = f(targetWidth - width, d);
if (x < 0) {
if (xDelay < delay) {
xDelay++;
x = 0;
}
} else {
xDelay = 0;
}
int y = f(targetHeight - height, d);
if (y < 0) {
if (yDelay < delay) {
yDelay++;
y = 0;
}
} else {
yDelay = 0;
}
if (x != 0 || y != 0) {
synchronized (SizeAndAlphaAnimation.this) {
if (instantWidth)
instantWidth = false;
else
width += x;
}
height += y;
updater.updateSize(width, height);
}
}
private void updateAlpha() {
if (!updater.visible()) {
alpha = targetAlpha;
updater.updateAlpha(alpha);
return;
}
int a = f(targetAlpha - alpha, d * 3);
if (a != 0) {
alpha += a;
updater.updateAlpha(alpha);
}
}
@CallFromAnyThread_NonReentrant
public void targetSize(int width, int height) {
targetWidth = width;
targetHeight = height;
}
@CallFromAnyThread_NonReentrant
public void targetAlpha(int alpha) {
targetAlpha = alpha;
}
private int f(int x, int d) {
if (x == 0)
return 0;
int f = x / d;
if (f == 0)
return x > 0 ? 1 : -1;
return f;
}
@CallFromAnyThread_NonReentrant
public void instantWidth() {
updater.updateSize(targetWidth, height);
synchronized (this) {
width = targetWidth;
instantWidth = true;
}
}
@CallFromAnyThread_NonReentrant
public void dispose() {
if (isDisposed())
return;
disposed = true;
}
@CallFromAnyThread_NonReentrant
public boolean isDisposed() {
return disposed;
}
}