package net.jeeeyul.eclipse.themes.rendering.internal;
import net.jeeeyul.swtend.SWTExtensions;
import net.jeeeyul.swtend.ui.NinePatch;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
@SuppressWarnings("javadoc")
public class Shadow9PatchFactory {
private static ImageData blur(ImageData src, int radius) {
ImageData dest = new ImageData(src.width, src.height, src.depth, src.palette);
for (int x = 0; x < src.width; x++) {
for (int y = 0; y < src.height; y++) {
dest.setPixel(x, y, src.getPixel(x, y));
double a = 0;
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
int rx = x + dx;
int ry = y + dy;
a = a + getAlpha(src, rx, ry);
}
}
dest.setAlpha(x, y, limit(a / 9d));
}
}
return dest;
}
public static NinePatch createShadowPatch(RGB foreground, int radius, int shadowRadius) {
radius = Math.max(radius, 5);
shadowRadius = Math.max(shadowRadius, 1);
Rectangle shadow = new Rectangle(0, 0, radius * 3 + shadowRadius * 2, radius * 3 + shadowRadius * 2);
Rectangle shadowShape = SWTExtensions.INSTANCE.getShrinked(shadow, shadowRadius);
ImageData shadowData = generateShadowImageData(shadow.width, shadow.height, shadowShape, radius, foreground, shadowRadius);
NinePatch patch = new NinePatch(shadowData, SWTExtensions.INSTANCE.getShrinked(shadowShape, radius));
return patch;
}
private static void fill(ImageData data, int x, int y, int w, int h, RGB color, int radius, int alpha) {
Rectangle topLeft = new Rectangle(x, y, radius, radius);
Rectangle topRight = new Rectangle(x + w - radius, y, radius, radius);
Rectangle bottomLeft = new Rectangle(x, y + h - radius, radius, radius);
Rectangle bottomRight = new Rectangle(x + w - radius, y + h - radius, radius, radius);
if (radius > 0) {
for (int cx = x; cx < x + w; cx++) {
for (int cy = y; cy < y + h; cy++) {
if (SWTExtensions.INSTANCE.contains(topLeft, cx, cy)) {
int ox = topLeft.x + topLeft.width;
int oy = topLeft.y + topLeft.height;
if (getDistance(cx, cy, ox, oy) <= radius) {
setRGB(data, cx, cy, color, alpha);
}
} else if (SWTExtensions.INSTANCE.contains(topRight, cx, cy)) {
int ox = topRight.x;
int oy = topRight.y + topRight.height;
if (getDistance(cx, cy, ox, oy) <= radius) {
setRGB(data, cx, cy, color, alpha);
}
} else if (SWTExtensions.INSTANCE.contains(bottomLeft, cx, cy)) {
int ox = bottomLeft.x + bottomLeft.width;
int oy = bottomLeft.y;
if (getDistance(cx, cy, ox, oy) <= radius) {
setRGB(data, cx, cy, color, alpha);
}
} else if (SWTExtensions.INSTANCE.contains(bottomRight, cx, cy)) {
int ox = bottomRight.x;
int oy = bottomRight.y;
if (getDistance(cx, cy, ox, oy) <= radius) {
setRGB(data, cx, cy, color, alpha);
}
} else {
setRGB(data, cx, cy, color, alpha);
}
}
}
} else {
for (int cx = x; cx < x + w; cx++) {
for (int cy = y; cy < y + h; cy++) {
setRGB(data, cx, cy, color, alpha);
}
}
}
}
private static ImageData generateShadowImageData(int width, int height, Rectangle rectangle, int cornerRadius, RGB shadowColor, int shadowRadius) {
ImageData result = new ImageData(width, height, 32, new PaletteData(0xff0000, 0xff00, 0xff));
fill(result, 0, 0, width, height, shadowColor, 0, 0);
fill(result, rectangle.x, rectangle.y, rectangle.width, rectangle.height, shadowColor, cornerRadius, 255);
for (int i = 0; i < shadowRadius; i++) {
result = blur(result, shadowRadius);
}
return result;
}
private static int getAlpha(ImageData data, int x, int y) {
x = Math.min(Math.max(0, x), data.width - 1);
y = Math.min(Math.max(0, y), data.height - 1);
return data.getAlpha(x, y);
}
private static int getDistance(int x1, int y1, int x2, int y2) {
int dx = x2 - x1;
int dy = y2 - y1;
return (int) Math.sqrt(dx * dx + dy * dy);
}
private static int limit(double v) {
return (int) Math.min(Math.max(v, 0), 255);
}
public static void main(String[] args) {
Display display = Display.getDefault();
final NinePatch patch = createShadowPatch(new RGB(255, 0, 0), 40, 40);
Shell shell = new Shell(display);
shell.addListener(SWT.Paint, new Listener() {
@Override
public void handleEvent(Event event) {
patch.fill(event.gc, new Rectangle(200, 0, 300, 300));
event.gc.drawRectangle(new Rectangle(200, 0, 300, 300));
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
private static void setRGB(ImageData data, int x, int y, RGB rgb, int alpha) {
data.setPixel(x, y, data.palette.getPixel(rgb));
data.setAlpha(x, y, alpha);
}
public Shadow9PatchFactory() {
}
}