AnimationRunner.java
package swingtree.animation;
import swingtree.style.ComponentExtension;
import javax.swing.JComponent;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* This is a singleton class responsible for running {@link ComponentAnimator}
* instances (which are wrapper classes for {@link Animation} instances)
* in a regular interval based on a Swing {@link Timer}.
* The timer is started when the first animation is scheduled and stopped when the last animation is finished.
*/
class AnimationRunner
{
private static final Map<Integer,AnimationRunner> _INSTANCES = new HashMap<>();
public static void add( ComponentAnimator animator ) {
Objects.requireNonNull(animator);
int interval = (int) animator.lifeSpan().lifeTime().getIntervalIn(TimeUnit.MILLISECONDS);
AnimationRunner runner = _INSTANCES.computeIfAbsent(interval, it -> new AnimationRunner(interval));
runner._add(animator);
}
private final Timer _timer;
private final List<ComponentAnimator> _animators = new ArrayList<>();
private final List<JComponent> _toBeCleaned = new ArrayList<>();
private AnimationRunner( int delay ) {
_timer = new Timer( delay, this::_run );
}
private void _run( ActionEvent event ) {
for ( JComponent component : new ArrayList<>(_toBeCleaned) ) {
ComponentExtension.from(component).clearAnimations();
_toBeCleaned.remove(component);
}
if ( _animators.isEmpty() && _toBeCleaned.isEmpty() ) {
_timer.stop();
// We can remove the instance from the map since it's not needed anymore
_INSTANCES.remove(_timer.getDelay());
return;
}
for ( ComponentAnimator animator : new ArrayList<>(_animators) )
animator.component().ifPresent( component -> {
ComponentExtension.from(component).clearAnimations();
});
long now = System.currentTimeMillis();
for ( ComponentAnimator animator : new ArrayList<>(_animators) )
if ( !animator.run(now, event) ) {
_animators.remove(animator);
animator.component().ifPresent( _toBeCleaned::add );
}
}
private void _add( ComponentAnimator animator ) {
Objects.requireNonNull(animator, "Null is not a valid animator!");
_animators.add(animator);
if ( !_timer.isRunning() )
_timer.start();
}
}