package org.objectstyle.wolips.componenteditor.inspector;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
public class PopAnimator implements PaintListener {
private static final int minBorderWidth = 2;
private static final int maxBorderWidth = 6;
private static final int animationDuration = 150;
private static final int borderRadius = 10;
private static final int borderRedrawSize = maxBorderWidth * 2;
private boolean _isAnimating;
private long _startTime;
private Rectangle _animationRect;
private Color _backgroundColor;
private Control _control;
public PopAnimator() {
RGB bindingHoverColorPreference = new RGB(240, 220, 0);
_backgroundColor = new Color(Display.getCurrent(), bindingHoverColorPreference);
}
public void setControl(Control control) {
if (_control != null && !_control.isDisposed()) {
_control.removePaintListener(this);
}
_control = control;
if (_control != null) {
_control.addPaintListener(this);
}
}
public void setAnimationRect(Rectangle animationRect) {
repaint();
_animationRect = animationRect;
}
public void step() {
if (isAnimating()) {
repaint();
}
}
public void repaint() {
repaint(_animationRect);
}
public void repaint(Rectangle rect) {
if (_control != null && rect != null) {
_control.redraw(rect.x - borderRedrawSize, rect.y - borderRedrawSize, rect.width + 2 * borderRedrawSize, rect.height + 2 * borderRedrawSize, true);
}
}
public boolean isAnimating() {
return _isAnimating;
}
public void dispose() {
setControl(null);
if (_backgroundColor != null) {
_backgroundColor.dispose();
}
_backgroundColor = null;
}
public synchronized void stopAnimation() {
_isAnimating = false;
Rectangle animationRect = _animationRect;
_animationRect = null;
if (animationRect != _animationRect) {
repaint(animationRect);
}
}
public synchronized void startAnimation() {
_startTime = System.currentTimeMillis();
_isAnimating = true;
repaint();
}
public void paintControl(PaintEvent e) {
try {
boolean shouldThrob;
double animationTime;
Rectangle selectionRect;
synchronized (this) {
// Determine whether or not the animation should still be
// running
animationTime = System.currentTimeMillis() - _startTime;
if (_isAnimating && animationTime > 2 * animationDuration) {
_isAnimating = false;
}
if (_animationRect != null) {
selectionRect = new Rectangle(_animationRect.x, _animationRect.y, _animationRect.width, _animationRect.height);
} else {
selectionRect = null;
}
shouldThrob = _isAnimating;
}
if (_animationRect != null) {
// Set the line width based on the animation curve
int lineWidth = minBorderWidth;
if (shouldThrob) {
lineWidth += (int) ((maxBorderWidth - minBorderWidth) * Math.sin(0.5 * Math.PI * animationTime / animationDuration));
}
int margin = lineWidth / 2;
if (lineWidth > 0) {
e.gc.setLineWidth(lineWidth);
// Set the rectangle size according to the current animation
// position
selectionRect.x -= margin;
selectionRect.y -= margin;
selectionRect.width += 2 * margin;
selectionRect.height += 2 * margin;
// Make selections on the edge look a little nicer
if (selectionRect.x < minBorderWidth / 2) {
selectionRect.x += minBorderWidth;
selectionRect.width -= minBorderWidth;
}
if (selectionRect.y < minBorderWidth / 2) {
selectionRect.y += minBorderWidth;
selectionRect.height -= minBorderWidth;
}
// Draw the shadow -- we have to cheat some here, because
// the text is rendered underneath us, so we can only render
// the bottom of the shadow
if (true || lineWidth > minBorderWidth) {
int shadowHeight = 2 * margin;
int shadowMargin = borderRadius / 2 + 2 * margin;
e.gc.setAlpha(80);
e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_BLACK));
e.gc.drawRoundRectangle(selectionRect.x + shadowMargin, selectionRect.y + selectionRect.height, selectionRect.width - 2 * shadowMargin, shadowHeight, borderRadius, borderRadius);
}
e.gc.setForeground(_backgroundColor);
e.gc.setBackground(_backgroundColor);
// Fill the rectangle with a light color for multiline
// selections
e.gc.setAlpha(50);
e.gc.fillRoundRectangle(selectionRect.x, selectionRect.y, selectionRect.width, selectionRect.height, borderRadius, borderRadius);
// And now draw the border of the rectangle in full opaque
e.gc.setAlpha(255);
e.gc.drawRoundRectangle(selectionRect.x, selectionRect.y, selectionRect.width, selectionRect.height, borderRadius, borderRadius);
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}