/** * */ package com.aelitis.azureus.ui.swt.skin; import java.util.ArrayList; import org.eclipse.swt.SWT; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.widgets.*; import org.gudy.azureus2.core3.util.AERunnable; import org.gudy.azureus2.core3.util.Constants; import org.gudy.azureus2.core3.util.Debug; import org.gudy.azureus2.ui.swt.Utils; import com.aelitis.azureus.ui.swt.imageloader.ImageLoader; /** * @author TuxPaper * @created Jun 8, 2006 * */ public class SWTBGImagePainter implements Listener { private static boolean DEBUG = false; private static boolean TEST_SWT_PAINTING = false; //Constants.isOSX; private Rectangle lastResizeRect = Utils.EMPTY_RECT; private final Shell shell; private String imgSrcID; private String imgSrcLeftID; private String imgSrcRightID; private Image imgSrc; private Image imgSrcLeft; private Image imgSrcRight; private Rectangle imgSrcBounds; private Rectangle imgSrcLeftBounds; private Rectangle imgSrcRightBounds; private Image lastImage = null; boolean inEvent = false; Rectangle lastBounds = Utils.EMPTY_RECT; Point lastShellBGSize = new Point(0, 0); private final int tileMode; private final Control control; private boolean bDirty; private int fdWidth = -1; private int fdHeight = -1; private ImageLoader imageLoader = null; private SWTBGImagePainter(Control control, int tileMode) { this.control = control; this.shell = control.getShell(); this.tileMode = tileMode; control.setData("BGPainter", this); } public SWTBGImagePainter(Control control, Image bgImage, int tileMode) { this(control, null, null, bgImage, tileMode); } public SWTBGImagePainter(Control control, Image bgImageLeft, Image bgImageRight, Image bgImage, int tileMode) { this(control, tileMode); setImages(bgImageLeft, bgImageRight, bgImage); if (bDirty) { if (control.isVisible()) { buildBackground(control); } } if (!TEST_SWT_PAINTING) { control.addListener(SWT.Resize, this); control.addListener(SWT.Paint, this); control.getShell().addListener(SWT.Show, this); } control.addListener(SWT.Dispose, this); } public SWTBGImagePainter(Control control, ImageLoader imageLoader, String bgImageLeftId, String bgImageRightId, String bgImageId, int tileMode) { this(control, tileMode); setImage(imageLoader, bgImageLeftId, bgImageRightId, bgImageId); if (bDirty) { if (control.isVisible()) { buildBackground(control); } } if (!TEST_SWT_PAINTING) { control.addListener(SWT.Resize, this); control.addListener(SWT.Paint, this); control.getShell().addListener(SWT.Show, this); } control.addListener(SWT.Dispose, this); } public void dispose() { if (control == null || control.isDisposed()) { return; } if (!TEST_SWT_PAINTING) { control.removeListener(SWT.Resize, this); control.removeListener(SWT.Paint, this); control.getShell().removeListener(SWT.Show, this); } control.removeListener(SWT.Dispose, this); control.setBackgroundImage(null); FormData formData = (FormData) control.getLayoutData(); formData.width = SWT.DEFAULT; formData.height = SWT.DEFAULT; control.setData("BGPainter", null); } /** * @param bgImageLeft * @param bgImageRight * @param bgImage */ public void setImage(Image bgImageLeft, Image bgImageRight, Image bgImage) { setImages(bgImageLeft, bgImageRight, bgImage); if (bDirty) { Utils.execSWTThread(new AERunnable() { public void runSupport() { if (!control.isVisible()) { return; } buildBackground(control); } }); } } public void setImage(ImageLoader imageLoader, String idLeft, String idRight, String id) { setImages(imageLoader, idLeft, idRight, id); if (bDirty) { Utils.execSWTThread(new AERunnable() { public void runSupport() { if (!control.isVisible()) { return; } buildBackground(control); } }); } } private boolean imagesEqual(Image image1, Image image2) { if (image1 == image2) { return true; } if (!ImageLoader.isRealImage(image1) && !ImageLoader.isRealImage(image2)) { return true; } return false; } private void setImages(Image bgImageLeft, Image bgImageRight, Image bgImage) { if (imagesEqual(imgSrc, bgImage) && imagesEqual(imgSrcLeft, bgImageLeft) && imagesEqual(imgSrcRight, bgImageRight)) { if (DEBUG) { System.out.println("same"); } return; } imgSrcLeftID = null; imgSrcRightID = null; imgSrcID = null; if (DEBUG) { System.out.println("SI " + bgImageLeft + ";" + bgImageRight + ";" + bgImage + ";" + control.getData("SkinObject") + "/" + control.isVisible() + control.getSize() + "\\" + Debug.getStackTrace(true, false)); } imgSrc = bgImage; if (imgSrc != null) { imgSrcBounds = imgSrc.getBounds(); } lastShellBGSize = new Point(0, 0); if (ImageLoader.isRealImage(bgImageLeft)) { imgSrcLeft = bgImageLeft; imgSrcLeftBounds = imgSrcLeft.getBounds(); } else { imgSrcLeft = null; imgSrcLeftBounds = Utils.EMPTY_RECT; } if (ImageLoader.isRealImage(bgImageRight)) { imgSrcRight = bgImageRight; imgSrcRightBounds = imgSrcRight.getBounds(); } else { imgSrcRight = null; imgSrcRightBounds = Utils.EMPTY_RECT; } if (TEST_SWT_PAINTING) { control.removeListener(SWT.Resize, this); control.removeListener(SWT.Paint, this); if (imgSrcRight == null && imgSrcLeft == null && tileMode == SWTSkinUtils.TILE_NONE) { control.setBackgroundImage(imgSrc); } else { control.addListener(SWT.Resize, this); control.addListener(SWT.Paint, this); bDirty = true; buildBackground(control); } } else { bDirty = true; } if ((tileMode & SWTSkinUtils.TILE_BOTH) != SWTSkinUtils.TILE_BOTH) { int width = SWT.DEFAULT; int height = SWT.DEFAULT; if (tileMode == SWTSkinUtils.TILE_Y || tileMode == SWTSkinUtils.TILE_NONE) { width = imgSrcBounds.width + imgSrcLeftBounds.width + imgSrcRightBounds.width; } if (tileMode == SWTSkinUtils.TILE_X || tileMode == SWTSkinUtils.TILE_NONE) { height = imgSrcBounds.height; } FormData fd = (FormData) control.getLayoutData(); if (fd == null) { fd = new FormData(); } if (fd.width == fdWidth || fd.height == fdHeight) { if (fd.width == fdWidth) { fdWidth = fd.width = width; } if (fd.height == fdHeight) { fdHeight = fd.height = height; } control.setLayoutData(fd); if (control.isVisible()) { bDirty = true; control.getParent().layout(true, true); } } } } /** * @param bgImageLeftId * @param bgImageRightId * @param bgImageId * * @since 4.0.0.5 */ public void setImages(ImageLoader imageLoader, String bgImageLeftId, String bgImageRightId, String bgImageId) { this.imageLoader = imageLoader; imgSrcLeftID = bgImageLeftId; imgSrcRightID = bgImageRightId; imgSrcID = bgImageId; imgSrcLeftBounds = Utils.EMPTY_RECT; imgSrcRightBounds = Utils.EMPTY_RECT; if (imgSrcID != null) { Image imgSrc = imageLoader.getImage(imgSrcID); imgSrcBounds = imgSrc.getBounds(); imageLoader.releaseImage(imgSrcID); } Image imgSrcLeft = imageLoader.getImage(imgSrcLeftID); if (ImageLoader.isRealImage(imgSrcLeft)) { imgSrcLeftBounds = imgSrcLeft.getBounds(); } imageLoader.releaseImage(imgSrcLeftID); Image imgSrcRight = imageLoader.getImage(imgSrcRightID); if (ImageLoader.isRealImage(imgSrcRight)) { imgSrcRightBounds = imgSrcRight.getBounds(); } imageLoader.releaseImage(imgSrcRightID); if (TEST_SWT_PAINTING) { control.removeListener(SWT.Resize, this); control.removeListener(SWT.Paint, this); control.addListener(SWT.Resize, this); control.addListener(SWT.Paint, this); bDirty = true; buildBackground(control); } else { bDirty = true; } if ((tileMode & SWTSkinUtils.TILE_BOTH) != SWTSkinUtils.TILE_BOTH) { int width = SWT.DEFAULT; int height = SWT.DEFAULT; if (tileMode == SWTSkinUtils.TILE_Y || tileMode == SWTSkinUtils.TILE_NONE) { width = imgSrcBounds.width + imgSrcLeftBounds.width + imgSrcRightBounds.width; } if (tileMode == SWTSkinUtils.TILE_X || tileMode == SWTSkinUtils.TILE_NONE) { height = imgSrcBounds.height; } FormData fd = (FormData) control.getLayoutData(); if (fd == null) { fd = new FormData(); } if (fd.width == fdWidth || fd.height == fdHeight) { if (fd.width == fdWidth) { fdWidth = fd.width = width; } if (fd.height == fdHeight) { fdHeight = fd.height = height; } control.setLayoutData(fd); if (control.isVisible()) { bDirty = true; control.getParent().layout(true, true); } } } } public void buildBackground(Control control) { if (inEvent || shell == null || shell.isDisposed() || control == null || control.isDisposed()) { return; } //System.out.println("BB: " + control.getData("ConfigID")); inEvent = true; ArrayList<String> imagesToRelease = new ArrayList<String>(0); if (imgSrcLeftID != null && imageLoader.imageExists(imgSrcLeftID)) { imagesToRelease.add(imgSrcLeftID); imgSrcLeft = imageLoader.getImage(imgSrcLeftID); imgSrcLeftBounds = imgSrcLeft.getBounds(); } if (imgSrcRightID != null && imageLoader.imageExists(imgSrcRightID)) { imagesToRelease.add(imgSrcRightID); imgSrcRight = imageLoader.getImage(imgSrcRightID); imgSrcRightBounds = imgSrcRight.getBounds(); } if (imgSrcID != null) { Image[] images = imageLoader.getImages(imgSrcID); imagesToRelease.add(imgSrcID); if (images.length == 1) { imgSrc = images[0]; imgSrcBounds = imgSrc.getBounds(); } else if (images.length == 2) { imgSrcLeft = images[0]; imgSrcLeftBounds = imgSrcLeft.getBounds(); imgSrc = images[1]; imgSrcBounds = imgSrc.getBounds(); imgSrcRight = images[1]; imgSrcRightBounds = imgSrcRight.getBounds(); } else if (images.length == 3) { imgSrcLeft = images[0]; imgSrcLeftBounds = imgSrcLeft.getBounds(); imgSrc = images[1]; imgSrcBounds = imgSrc.getBounds(); imgSrcRight = images[2]; imgSrcRightBounds = imgSrcRight.getBounds(); } } try { Point size = control.getSize(); if (size.x <= 0 || size.y <= 0 || imgSrc == null || imgSrc.isDisposed()) { if (DEBUG) { System.out.println("- size " + control.getData("ConfigID")); } Image image = new Image(shell.getDisplay(), 1, 1); control.setBackgroundImage(image); if (lastImage != null) { lastImage.dispose(); } lastImage = image; imgSrc = image; imgSrcBounds = new Rectangle(0,0,1,1); lastBounds = control.getBounds(); inEvent = false; return; } Composite parent = control.getParent(); Image imgBG = parent.getBackgroundImage(); if (imgBG != null && imgBG.isDisposed()) { imgBG = null; } Rectangle imgBGBounds = imgBG == null ? new Rectangle(0, 0, 1, 1) : imgBG.getBounds(); Rectangle compositeArea = control.getBounds(); boolean bTileY = (tileMode & SWTSkinUtils.TILE_Y) > 0; boolean bTileX = (tileMode & SWTSkinUtils.TILE_X) > 0; // TODO: Can also exit early if size shrunk but position // same and imgBGBounds same. if (!bDirty && imgBG == null && bTileX && bTileY) { inEvent = false; return; } if (!bDirty && imgBG == null && compositeArea.width == lastBounds.width && compositeArea.height == lastBounds.height) { inEvent = false; return; } if (!bDirty && compositeArea.equals(lastBounds) && imgBGBounds.width == lastShellBGSize.x && imgBGBounds.height == lastShellBGSize.y) { inEvent = false; return; } if (TEST_SWT_PAINTING && !bDirty && compositeArea.width == lastBounds.width && compositeArea.height == lastBounds.height) { inEvent = false; return; } //control.setRedraw(false); if (DEBUG) { System.out.println(System.currentTimeMillis() + "@" + Integer.toHexString(hashCode()) + "BGPain: " + control.getData("SkinObject") + "/" + "; image" + size + ";" + tileMode + ";lB=" + lastBounds + "/" + compositeArea + ";" + "lBG=" + lastShellBGSize + "/" + imgBGBounds.width + "x" + imgBGBounds.height + ";" + bDirty); //+ "\n" + Debug.getCompressedStackTrace()); } lastBounds = compositeArea; lastShellBGSize = new Point(imgBGBounds.width, imgBGBounds.height); //System.out.println(size); //size.x = 10; //size.y = 10; Image newImage = new Image(shell.getDisplay(), size.x, size.y); // GC gc = new GC(newImage); // gc.setBackground(shell.getDisplay().getSystemColor( // (int) (Math.random() * 16))); // gc.fillRectangle(0, 0, size.x, size.y); // gc.dispose(); Point ofs; if (control.getParent() == shell) { ofs = control.getLocation(); Rectangle clientArea = shell.getClientArea(); ofs.x += clientArea.x; ofs.y += clientArea.y; } else { Point controlPos = new Point(0, 0); if (control instanceof Composite) { Composite composite = (Composite) control; Rectangle compArea = composite.getClientArea(); //System.out.println("comparea=" + compArea); controlPos.x = compArea.x; controlPos.y = compArea.y; } Point locControl = control.toDisplay(controlPos.x, controlPos.y); Rectangle clientArea = shell.getClientArea(); Point locShell = control.getParent().toDisplay(clientArea.x, clientArea.y); //System.out.println("locC="+ locControl + ";locS=" + locShell); ofs = new Point(locControl.x - locShell.x, locControl.y - locShell.y); } ofs.x = (ofs.x % imgBGBounds.width); ofs.y = (ofs.y % imgBGBounds.height); GC gc = new GC(newImage); try { control.setBackgroundImage(null); gc.setBackground(control.getBackground()); gc.fillRectangle(0, 0, size.x, size.y); if (imgBG != null) { for (int y = 0; y < size.y; y += imgBGBounds.height) { for (int x = 0; x < size.x; x += imgBGBounds.width) { gc.drawImage(imgBG, x - ofs.x, y - ofs.y); } } } int maxY = bTileY ? size.y : imgSrcBounds.height; int maxX = bTileX ? size.x : imgSrcBounds.width; int x0 = 0; if ((tileMode & SWTSkinUtils.TILE_CENTER_X) > 0) { x0 = (size.x - imgSrcBounds.width) / 2; maxX += x0; } int y0 = 0; if ((tileMode & SWTSkinUtils.TILE_CENTER_Y) > 0) { y0 = (size.y - imgSrcBounds.height) / 2; maxY += y0; } if (imgSrcRight != null) { int width = imgSrcRightBounds.width; maxX -= width; } if (imgSrcLeft != null) { // TODO: Tile down gc.drawImage(imgSrcLeft, 0, 0); x0 += imgSrcLeftBounds.width; } for (int y = y0; y < maxY; y += imgSrcBounds.height) { for (int x = x0; x < maxX; x += imgSrcBounds.width) { if (x + imgSrcBounds.width >= maxX) { int width = maxX - x; gc.drawImage(imgSrc, 0, 0, width, imgSrcBounds.height, x, y, width, imgSrcBounds.height); } else { gc.drawImage(imgSrc, x, y); } } } if (imgSrcRight != null) { // TODO: Tile down gc.drawImage(imgSrcRight, maxX, 0); } } finally { gc.dispose(); } control.setBackgroundImage(newImage); if (lastImage != null) { lastImage.dispose(); } lastImage = newImage; bDirty = false; } finally { for (String key : imagesToRelease) { imageLoader.releaseImage(key); } if (imgSrcID != null && imgSrc != null) { imgSrc = null; } if (imgSrcLeftID != null && imgSrcLeft != null) { imgSrcLeft = null; } if (imgSrcRightID != null && imgSrcRight != null) { imgSrcRight = null; } //control.setRedraw(true); //control.update(); //control.getShell().update(); // if (control instanceof Composite) { // Control[] children = ((Composite)control).getChildren(); // ((Composite)control).layout(true, true); // for (int i = 0; i < children.length; i++) { // Control control2 = children[i]; // control2.redraw(); // control2.update(); // } // } inEvent = false; } } public static void main(String[] args) { Display display = Display.getDefault(); Shell shell = new Shell(display, SWT.DIALOG_TRIM); shell.setLayout(new FillLayout()); Composite c = new Composite(shell, SWT.BORDER); c.setLayout(new FillLayout()); c.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) { e.gc.drawLine(0, 0, 100, 50); } }); Label lbl = new Label(c, SWT.NONE); lbl.setText("text"); shell.open(); while (!shell.isDisposed()) { if (display.readAndDispatch()) { display.sleep(); } } } public void handleEvent(final Event event) { if (event.type == SWT.Resize) { Control control = (Control) event.widget; Rectangle resizeRect = control.getBounds(); if (resizeRect.equals(lastResizeRect)) { return; } lastResizeRect = resizeRect; if (DEBUG) { System.out.println("BGPaint:HE: " + control.getData("ConfigID") + ";" + event + ";" + control.isVisible()); } buildBackground(control); } else if (event.type == SWT.Paint) { Control control = (Control) event.widget; if (DEBUG) { System.out.println("BGPaint:P: " + control.getData("ConfigID") + ";" + event + ";" + control.isVisible()); } if (!TEST_SWT_PAINTING) { buildBackground(control); } } else if (event.type == SWT.Show) { if (DEBUG) { System.out.println("BGPaint:S: " + control.getData("ConfigID") + ";" + event + ";" + control.isVisible()); } if (!TEST_SWT_PAINTING) { buildBackground(control); } } else if (event.type == SWT.Dispose) { if (DEBUG) { System.out.println("dispose.. " + lastImage + ";" + control.getData("SkinObject")); } if (lastImage != null && !lastImage.isDisposed()) { lastImage.dispose(); lastImage = null; } } } }