AnimationControllerpublic class AnimationController extends Object implements ActionListener, PropertyChangeListenerA class to help mimic Vista theme animations. The only kind of
animation it handles for now is 'transition' animation (this seems
to be the only animation which Vista theme can do). This is when
one picture fadein over another one in some period of time.
According to
https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=86852&SiteID=4
The animations are all linear.
This class has a number of responsibilities.
- It trigger rapaint for the UI components involved in the animation
- It tracks the animation state for every UI component involved in the
animation and paints {@code Skin} in new {@code State} over the
{@code Skin} in last {@code State} using
{@code AlphaComposite.SrcOver.derive(alpha)} where {code alpha}
depends on the state of animation
|
Fields Summary |
---|
private static final boolean | VISTA_ANIMATION_DISABLED | private static final Object | ANIMATION_CONTROLLER_KEY | private final Map | animationStateMap | private final Timer | timer |
Constructors Summary |
---|
private AnimationController()
timer.setRepeats(true);
timer.setCoalesce(true);
//we need to dispose the controller on l&f change
UIManager.addPropertyChangeListener(this);
|
Methods Summary |
---|
public synchronized void | actionPerformed(java.awt.event.ActionEvent e)
java.util.List<JComponent> componentsToRemove = null;
java.util.List<Part> partsToRemove = null;
for (JComponent component : animationStateMap.keySet()) {
component.repaint();
if (partsToRemove != null) {
partsToRemove.clear();
}
Map<Part, AnimationState> map = animationStateMap.get(component);
if (! component.isShowing()
|| map == null
|| map.size() == 0) {
if (componentsToRemove == null) {
componentsToRemove = new ArrayList<JComponent>();
}
componentsToRemove.add(component);
continue;
}
for (Part part : map.keySet()) {
if (map.get(part).isDone()) {
if (partsToRemove == null) {
partsToRemove = new ArrayList<Part>();
}
partsToRemove.add(part);
}
}
if (partsToRemove != null) {
if (partsToRemove.size() == map.size()) {
//animation is done for the component
if (componentsToRemove == null) {
componentsToRemove = new ArrayList<JComponent>();
}
componentsToRemove.add(component);
} else {
for (Part part : partsToRemove) {
map.remove(part);
}
}
}
}
if (componentsToRemove != null) {
for (JComponent component : componentsToRemove) {
animationStateMap.remove(component);
}
}
if (animationStateMap.size() == 0) {
timer.stop();
}
| private synchronized void | dispose()
timer.stop();
UIManager.removePropertyChangeListener(this);
synchronized (AnimationController.class) {
AppContext.getAppContext()
.put(ANIMATION_CONTROLLER_KEY, null);
}
| private static synchronized com.sun.java.swing.plaf.windows.AnimationController | getAnimationController()
AppContext appContext = AppContext.getAppContext();
Object obj = appContext.get(ANIMATION_CONTROLLER_KEY);
if (obj == null) {
obj = new AnimationController();
appContext.put(ANIMATION_CONTROLLER_KEY, obj);
}
return (AnimationController) obj;
| private synchronized com.sun.java.swing.plaf.windows.TMSchema.State | getState(javax.swing.JComponent component, com.sun.java.swing.plaf.windows.TMSchema.Part part)
State rv = null;
Object tmpObject =
component.getClientProperty(PartUIClientPropertyKey.getKey(part));
if (tmpObject instanceof State) {
rv = (State) tmpObject;
}
return rv;
| private static com.sun.java.swing.plaf.windows.TMSchema.State | normalizeState(com.sun.java.swing.plaf.windows.TMSchema.State state)
State rv;
switch (state) {
case DOWNPRESSED:
/* falls through */
case LEFTPRESSED:
/* falls through */
case RIGHTPRESSED:
rv = UPPRESSED;
break;
case DOWNDISABLED:
/* falls through */
case LEFTDISABLED:
/* falls through */
case RIGHTDISABLED:
rv = UPDISABLED;
break;
case DOWNHOT:
/* falls through */
case LEFTHOT:
/* falls through */
case RIGHTHOT:
rv = UPHOT;
break;
case DOWNNORMAL:
/* falls through */
case LEFTNORMAL:
/* falls through */
case RIGHTNORMAL:
rv = UPNORMAL;
break;
default :
rv = state;
break;
}
return rv;
| static void | paintSkin(javax.swing.JComponent component, com.sun.java.swing.plaf.windows.XPStyle.Skin skin, java.awt.Graphics g, int dx, int dy, int dw, int dh, com.sun.java.swing.plaf.windows.TMSchema.State state)
if (VISTA_ANIMATION_DISABLED) {
skin.paintSkinRaw(g, dx, dy, dw, dh, state);
return;
}
triggerAnimation(component, skin.part, state);
AnimationController controller = getAnimationController();
synchronized (controller) {
AnimationState animationState = null;
Map<Part, AnimationState> map =
controller.animationStateMap.get(component);
if (map != null) {
animationState = map.get(skin.part);
}
if (animationState != null) {
animationState.paintSkin(skin, g, dx, dy, dw, dh, state);
} else {
skin.paintSkinRaw(g, dx, dy, dw, dh, state);
}
}
| public synchronized void | propertyChange(java.beans.PropertyChangeEvent e)
if ("lookAndFeel" == e.getPropertyName()
&& ! (e.getNewValue() instanceof WindowsLookAndFeel) ) {
dispose();
}
| private synchronized void | putState(javax.swing.JComponent component, com.sun.java.swing.plaf.windows.TMSchema.Part part, com.sun.java.swing.plaf.windows.TMSchema.State state)
component.putClientProperty(PartUIClientPropertyKey.getKey(part),
state);
| private synchronized void | startAnimation(javax.swing.JComponent component, com.sun.java.swing.plaf.windows.TMSchema.Part part, com.sun.java.swing.plaf.windows.TMSchema.State startState, com.sun.java.swing.plaf.windows.TMSchema.State endState, long millis)
boolean isForwardAndReverse = false;
if (endState == State.DEFAULTED) {
isForwardAndReverse = true;
}
Map<Part, AnimationState> map = animationStateMap.get(component);
if (millis <= 0) {
if (map != null) {
map.remove(part);
if (map.size() == 0) {
animationStateMap.remove(component);
}
}
return;
}
if (map == null) {
map = new EnumMap<Part, AnimationState>(Part.class);
animationStateMap.put(component, map);
}
map.put(part,
new AnimationState(startState, millis, isForwardAndReverse));
if (! timer.isRunning()) {
timer.start();
}
| private static void | triggerAnimation(javax.swing.JComponent c, com.sun.java.swing.plaf.windows.TMSchema.Part part, com.sun.java.swing.plaf.windows.TMSchema.State newState)
if (c instanceof javax.swing.JTabbedPane
|| part == Part.TP_BUTTON) {
//idk: we can not handle tabs animation because
//the same (component,part) is used to handle all the tabs
//and we can not track the states
//Vista theme might have transition duration for toolbar buttons
//but native application does not seem to animate them
return;
}
AnimationController controller =
AnimationController.getAnimationController();
State oldState = controller.getState(c, part);
if (oldState != newState) {
controller.putState(c, part, newState);
if (newState == State.DEFAULTED) {
// it seems for DEFAULTED button state Vista does animation from
// HOT
oldState = State.HOT;
}
if (oldState != null) {
long duration;
if (newState == State.DEFAULTED) {
//Only button might have DEFAULTED state
//idk: do not know how to get the value from Vista
//one second seems plausible value
duration = 1000;
} else {
duration = XPStyle.getXP().getThemeTransitionDuration(
c, part,
normalizeState(oldState),
normalizeState(newState),
Prop.TRANSITIONDURATIONS);
}
controller.startAnimation(c, part, oldState, newState, duration);
}
}
|
|