/**
*
*/
package com.yoursway.swt.overlay;
import static com.yoursway.swt.additions.YsSwtUtils.lowerLeft;
import static com.yoursway.swt.additions.YsSwtUtils.setLowerLeft;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
public class TemporaryCanvasOverlay implements Overlay {
private final GC gc;
private final Canvas canvas;
private Image screenshot;
private final Rectangle bounds;
private final Control originalControl;
private Color erasedBackgroundColor;
public TemporaryCanvasOverlay(Control control, Rectangle bounds) {
if (control == null)
throw new NullPointerException("control is null");
if (bounds == null)
throw new NullPointerException("bounds is null");
this.originalControl = control;
control = findSuitableControl(control, bounds);
this.bounds = bounds;
makeScreenshot(control);
canvas = new Canvas((Composite) control, SWT.NO_BACKGROUND);
canvas.moveAbove(null);
canvas.setBounds(bounds);
this.gc = new GC(canvas);
drawOverlayBackgroundOnto(gc, new Rectangle(0, 0, bounds.width, bounds.height));
canvas.setBackground(new Color(null, 255, 0, 0));
gc.fillRectangle(new Rectangle(0, 0, bounds.width, bounds.height));
}
public Canvas getCanvas() {
return canvas;
}
private Control findSuitableControl(Control control, Rectangle bounds) {
Point screenPoint = control.toDisplay(bounds.x, bounds.y);
Rectangle controlBounds = control.getBounds();
while (bounds.x < 0 || bounds.y < 0 || bounds.x + bounds.width > controlBounds.width
|| bounds.y + bounds.height > controlBounds.height) {
Composite parent = control.getParent();
if (parent == null)
break;
control = parent;
Point controlPoint = control.toControl(screenPoint);
bounds.x = controlPoint.x;
bounds.y = controlPoint.y;
controlBounds = control.getBounds();
}
return control;
}
private void makeScreenshot(Control control) {
GC screenshotGc;
if (control instanceof Shell) {
Rectangle clientArea = ((Shell) control).getClientArea();
screenshot = new Image(control.getDisplay(), clientArea.width, clientArea.height);
Image temp = new Image(control.getDisplay(), clientArea.width, clientArea.height);
screenshotGc = new GC(screenshot);
GC tempGc = new GC(temp);
screenshotGc.setBackground(control.getBackground());
screenshotGc.fillRectangle(clientArea);
for (Control child : ((Shell) control).getChildren()) {
Rectangle bounds = child.getBounds();
tempGc.drawImage(screenshot, bounds.x, bounds.y, bounds.width, bounds.height, 0, 0,
bounds.width, bounds.height);
child.print(tempGc);
screenshotGc.drawImage(temp, 0, 0, bounds.width, bounds.height, bounds.x, bounds.y,
bounds.width, bounds.height);
}
tempGc.dispose();
temp.dispose();
} else {
Point screenshotSize = control.getSize();
screenshot = new Image(control.getDisplay(), screenshotSize.x, screenshotSize.y);
screenshotGc = new GC(screenshot);
control.print(screenshotGc);
}
// remove the control being flipped
if (erasedBackgroundColor != null) {
screenshotGc.setBackground(erasedBackgroundColor);
Rectangle boundsToErase = originalControl.getBounds();
Point pt = control.toControl(originalControl.getParent().toDisplay(lowerLeft(boundsToErase)));
setLowerLeft(boundsToErase, pt);
screenshotGc.fillRectangle(boundsToErase);
}
screenshotGc.dispose();
if (false) {
Shell s = new Shell((Shell) null, SWT.DIALOG_TRIM);
s.setText("Screenshot");
Rectangle sb = screenshot.getBounds();
Rectangle rect = s.computeTrim(50, 50, sb.width, sb.height);
s.setBounds(rect);
s.open();
GC gc2 = new GC(s);
gc2.drawImage(screenshot, 0, 0);
}
}
public void dispose() {
gc.dispose();
canvas.dispose();
screenshot.dispose();
}
public Rectangle getBounds() {
return bounds;
}
public void drawOverlayBackgroundOnto(GC gc, Rectangle targetBounds) {
targetBounds = new Rectangle(targetBounds.x, targetBounds.y, targetBounds.width, targetBounds.height);
if (true) {
gc.setBackground(new Color(null, 255, 0, 0));
gc.fillRectangle(targetBounds);
}
Rectangle sourceBounds = new Rectangle(bounds.x, bounds.y, targetBounds.width, targetBounds.height);
Rectangle imageBounds = screenshot.getBounds();
if (sourceBounds.x + sourceBounds.width > imageBounds.width)
sourceBounds.width = imageBounds.width - sourceBounds.x;
if (sourceBounds.y + sourceBounds.height > imageBounds.height)
sourceBounds.height = imageBounds.height - sourceBounds.y;
if (sourceBounds.x < imageBounds.x) {
sourceBounds.width -= (imageBounds.x - sourceBounds.x);
targetBounds.x += (imageBounds.x - sourceBounds.x);
sourceBounds.x = imageBounds.x;
}
if (sourceBounds.y < imageBounds.y) {
sourceBounds.height -= (imageBounds.y - sourceBounds.y);
targetBounds.y += (imageBounds.y - sourceBounds.y);
sourceBounds.y = imageBounds.y;
}
gc.drawImage(screenshot, sourceBounds.x, sourceBounds.y, sourceBounds.width, sourceBounds.height,
targetBounds.x, targetBounds.y, sourceBounds.width, sourceBounds.height);
}
public void renderOffscreenImage(Image offscreenImage) {
gc.drawImage(offscreenImage, 0, 0);
}
public void enableBackgroundErasing(Color color) {
this.erasedBackgroundColor = color;
}
public void disposeWithFadeout(final Image sourceImage, final int delay) {
final Image image = new Image(canvas.getDisplay(), bounds.width, bounds.height);
final GC gc = new GC(image);
new Thread("Fadeout animation") {
{
setDaemon(true);
}
@Override
public void run() {
try {
long endTime = System.currentTimeMillis() + delay;
while (true) {
int remainder = (int) (endTime - System.currentTimeMillis());
if (remainder < 0)
break;
int alpha = 255 * remainder / delay;
gc.setAlpha(255);
drawOverlayBackgroundOnto(gc, image.getBounds());
gc.setAlpha(alpha);
gc.drawImage(sourceImage, 0, 0);
renderOffscreenImage(image);
try {
Thread.sleep(1000 / 30);
} catch (InterruptedException e) {
}
}
} finally {
canvas.getDisplay().asyncExec(new Runnable() {
public void run() {
gc.dispose();
image.dispose();
sourceImage.dispose();
dispose();
}
});
}
}
}.start();
}
}