package org.tessell.util;
import static org.tessell.widgets.Widgets.newAnimation;
import java.util.ArrayList;
import org.tessell.gwt.animation.client.AnimationLogic;
import org.tessell.gwt.animation.client.IsAnimation;
import org.tessell.gwt.dom.client.IsElement;
import org.tessell.gwt.user.client.ui.IsWidget;
import com.google.gwt.dom.client.Style.Display;
/** JQuery-style effects that work against an {@link IsElement}. */
public class Effects {
public static Effects effects(IsWidget w) {
return effects(w.getIsElement());
}
public static Effects effects(IsElement e) {
return new Effects(e);
}
private final IsElement e;
private final ArrayList<QueuedEffect> effects = new ArrayList<QueuedEffect>();
private boolean running;
private Effects(IsElement e) {
this.e = e;
}
public Effects delay(int millis) {
effects.add(new QueuedEffect(new AnimationLogic() {
public void onUpdate(double progress) {
// do nothing
}
}, millis, null));
runNextIfNeeded();
return this;
}
public Effects fadeIn() {
effects.add(new QueuedEffect(new AnimationLogic() {
@Override
public void onUpdate(double progress) {
e.getStyle().setOpacity(progress);
}
@Override
public void onStart() {
super.onStart();
e.getStyle().clearDisplay();
}
}, 350, null));
runNextIfNeeded();
return this;
}
public Effects fadeOut() {
effects.add(new QueuedEffect(new AnimationLogic() {
@Override
public void onUpdate(double progress) {
e.getStyle().setOpacity(1 - progress);
}
}, 350, null));
runNextIfNeeded();
return this;
}
public Effects drop() {
effects.add(new QueuedEffect(new AnimationLogic() {
public void onUpdate(double progress) {
// do nothing
}
public void onComplete() {
e.removeFromParent();
}
}, 0, null));
runNextIfNeeded();
return this;
}
public Effects hide() {
effects.add(new QueuedEffect(new AnimationLogic() {
public void onUpdate(double progress) {
// do nothing
}
public void onComplete() {
e.getStyle().setDisplay(Display.NONE);
}
}, 0, null));
runNextIfNeeded();
return this;
}
private void runNextIfNeeded() {
if (running || effects.size() == 0) {
return;
}
final QueuedEffect next = effects.remove(0);
IsAnimation wrapper = newAnimation(new AnimationLogic() {
@Override
public void onStart() {
next.logic.onStart();
}
@Override
public void onUpdate(double progress) {
next.logic.onUpdate(progress);
}
@Override
public void onComplete() {
next.logic.onComplete();
if (next.callback != null) {
next.callback.run();
}
running = false;
runNextIfNeeded();
}
@Override
public double interpolate(double progress) {
return next.logic.interpolate(progress);
}
});
running = true; // set running first in case duration=0
wrapper.run(next.duration);
}
/** DTO to store a pending animation in the queue. */
private static class QueuedEffect {
private final AnimationLogic logic;
private final int duration;
private final Runnable callback;
private QueuedEffect(AnimationLogic logic, int duration, Runnable callback) {
this.logic = logic;
this.duration = duration;
this.callback = callback;
}
}
}