diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java index 4d29c190884..7e340642da0 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java @@ -17,6 +17,7 @@ import org.eclipse.swt.accessibility.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.*; import org.eclipse.swt.widgets.*; /** @@ -717,26 +718,25 @@ public Rectangle computeTrim (int x, int y, int width, int height) { } return trim; } + Image createButtonImage(Display display, int button) { - return new Image(display, (ImageDataProvider) zoom -> { - GC tempGC = new GC (CTabFolder.this); - Point size = renderer.computeSize(button, SWT.NONE, tempGC, SWT.DEFAULT, SWT.DEFAULT); - tempGC.dispose(); - - Rectangle trim = renderer.computeTrim(button, SWT.NONE, 0, 0, 0, 0); - Image image = new Image (display, size.x - trim.width, size.y - trim.height); - GC gc = new GC (image); - Color transColor = renderer.parent.getBackground(); - gc.setBackground(transColor); - gc.fillRectangle(image.getBounds()); - renderer.draw(button, SWT.NONE, new Rectangle(trim.x, trim.y, size.x, size.y), gc); - gc.dispose (); - - final ImageData imageData = image.getImageData (zoom); - imageData.transparentPixel = imageData.palette.getPixel(transColor.getRGB()); - image.dispose(); - return imageData; - }); + final GC tempGC = new GC (CTabFolder.this); + final Point size = renderer.computeSize(button, SWT.NONE, tempGC, SWT.DEFAULT, SWT.DEFAULT); + tempGC.dispose(); + + final Rectangle trim = renderer.computeTrim(button, SWT.NONE, 0, 0, 0, 0); + final Point imageSize = new Point(size.x - trim.width, size.y - trim.height); + Color transColor = renderer.parent.getBackground(); + final ImageGcDrawer imageGcDrawer = new TransparencyColorImageGcDrawer(transColor) { + @Override + public void drawOn(GC gc, int imageWidth, int imageHeight) { + Rectangle imageBounds = new Rectangle(0, 0, imageWidth, imageHeight); + gc.setBackground(transColor); + gc.fillRectangle(imageBounds); + renderer.draw(button, SWT.NONE, imageBounds, gc); + } + }; + return new Image(display, imageGcDrawer, imageSize.x, imageSize.y); } private void notifyItemCountChange() { diff --git a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java index f20ab4fc55c..97d16b8891f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/graphics/Image.java @@ -15,6 +15,7 @@ import java.io.*; +import java.util.*; import org.eclipse.swt.*; import org.eclipse.swt.internal.*; @@ -135,6 +136,11 @@ public final class Image extends Resource implements Drawable { */ private ImageDataProvider imageDataProvider; + /** + * ImageGcDrawer to provide a callback to draw on a GC for various zoom levels + */ + private ImageGcDrawer imageGcDrawer; + /** * Style flag used to differentiate normal, gray-scale and disabled images based * on image data providers. Without this, a normal and a disabled image of the @@ -384,8 +390,9 @@ public Image(Device device, Image srcImage, int flag) { imageFileNameProvider = srcImage.imageFileNameProvider; imageDataProvider = srcImage.imageDataProvider; + imageGcDrawer = srcImage.imageGcDrawer; this.styleFlag = srcImage.styleFlag | flag; - if (imageFileNameProvider != null || imageDataProvider != null) { + if (imageFileNameProvider != null || imageDataProvider != null ||srcImage.imageGcDrawer != null) { /* If source image has 200% representation then create the 200% representation for the new image & apply flag */ NSBitmapImageRep rep200 = srcImage.getRepresentation (200); if (rep200 != null) createRepFromSourceAndApplyFlag(rep200, srcWidth * 2, srcHeight * 2, flag); @@ -843,6 +850,54 @@ public Image(Device device, ImageDataProvider imageDataProvider) { } } +/** + * The provided ImageGcDrawer will be called on demand whenever a new variant of the + * Image for an additional zoom is required. Depending on the OS specific implementation + * these calls will be done during the instantiation or later when a new variant is + * requested. + * + * @param device the device on which to create the image + * @param imageGcDrawer the ImageGcDrawer object to be called when a new image variant + * for another zoom is required. + * @param width the width of the new image in points + * @param height the height of the new image in points + * + * @exception IllegalArgumentException + * @since 3.129 + */ +public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { + super(device); + if (imageGcDrawer == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); + this.imageGcDrawer = imageGcDrawer; + ImageData data = drawWithImageGcDrawer(imageGcDrawer, width, height, 100); + if (data == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT); + NSAutoreleasePool pool = null; + if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); + try { + init (data); + init (); + } finally { + if (pool != null) pool.release(); + } +} + +private ImageData drawWithImageGcDrawer(ImageGcDrawer imageGcDrawer, int width, int height, int zoom) { + Image image = new Image(device, width, height); + GC gc = new GC(image); + try { + imageGcDrawer.drawOn(gc, width, height); + ImageData imageData = image.getImageData(zoom); + imageGcDrawer.postProcess(imageData); + return imageData; + } finally { + gc.dispose(); + image.dispose(); + } +} + private AlphaInfo _getAlphaInfoAtCurrentZoom (NSBitmapImageRep rep) { int deviceZoom = DPIUtil.getDeviceZoom(); if (deviceZoom != 100 && (imageFileNameProvider != null || imageDataProvider != null)) { @@ -1121,6 +1176,9 @@ public boolean equals (Object object) { return styleFlag == image.styleFlag && imageDataProvider.equals (image.imageDataProvider); } else if (imageFileNameProvider != null && image.imageFileNameProvider != null) { return styleFlag == image.styleFlag && imageFileNameProvider.equals (image.imageFileNameProvider); + } else if (imageGcDrawer != null && image.imageGcDrawer != null) { + return styleFlag == image.styleFlag && imageGcDrawer.equals(image.imageGcDrawer) && width == image.width + && height == image.height; } else { return handle == image.handle; } @@ -1357,6 +1415,8 @@ public int hashCode () { return imageDataProvider.hashCode(); } else if (imageFileNameProvider != null) { return imageFileNameProvider.hashCode(); + } else if (imageGcDrawer != null) { + return Objects.hash(imageGcDrawer, height, width); } else { return handle != null ? (int)handle.id : 0; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageGcDrawer.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageGcDrawer.java new file mode 100644 index 00000000000..0400a0c2fd4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageGcDrawer.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Yatta - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.graphics; + +/** + * Interface to provide a callback mechanism to draw on different GC instances + * depending on the zoom the image will be used for. A common use case is when + * the application is moved from a low DPI monitor to a high DPI monitor. This + * provides API which will be called by SWT during the image rendering. + * + * This interface needs to be implemented by client code to provide logic that + * draws on the empty GC on demand. + * + * @since 3.129 + */ +public interface ImageGcDrawer { + + /** + * Draws an image on a GC for a requested zoom level. + * + * @param gc The GC will draw on the underlying Image and is configured + * for the targeted zoom + * @param imageWidth The width of the image in points to draw on + * @param imageHeight The height of the image in points to draw on + */ + void drawOn(GC gc, int imageWidth, int imageHeight); + + /** + * Executes post processing on ImageData. This method will always be called + * after drawOn and contain the resulting ImageData. + * + * @param imageData The resulting ImageData after drawOn was called + */ + default void postProcess(ImageData imageData) { + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/TransparencyColorImageGcDrawer.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/TransparencyColorImageGcDrawer.java new file mode 100644 index 00000000000..e7ee43332e9 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/TransparencyColorImageGcDrawer.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Yatta - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal; + +import org.eclipse.swt.graphics.*; + +public abstract class TransparencyColorImageGcDrawer implements ImageGcDrawer { + + private final Color transparencyColor; + + public TransparencyColorImageGcDrawer(Color transparencyColor) { + this.transparencyColor = transparencyColor; + } + + @Override + public void postProcess(ImageData imageData) { + imageData.transparentPixel = imageData.palette.getPixel(transparencyColor.getRGB()); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java index 2b48e4b34a5..b51af22f7eb 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Image.java @@ -15,6 +15,7 @@ import java.io.*; +import java.util.*; import org.eclipse.swt.*; import org.eclipse.swt.internal.*; @@ -151,6 +152,11 @@ public final class Image extends Resource implements Drawable { */ private ImageDataProvider imageDataProvider; + /** + * ImageGcDrawer to provide a callback to draw on a GC for various zoom levels + */ + private ImageGcDrawer imageGcDrawer; + /** * Style flag used to differentiate normal, gray-scale and disabled images based * on image data providers. Without this, a normal and a disabled image of the @@ -263,6 +269,7 @@ public Image(Device device, Image srcImage, int flag) { this.type = srcImage.type; this.imageDataProvider = srcImage.imageDataProvider; this.imageFileNameProvider = srcImage.imageFileNameProvider; + this.imageGcDrawer = srcImage.imageGcDrawer; this.styleFlag = srcImage.styleFlag | flag; this.currentDeviceZoom = srcImage.currentDeviceZoom; @@ -661,6 +668,36 @@ public Image(Device device, ImageDataProvider imageDataProvider) { init (); } +/** + * The provided ImageGcDrawer will be called on demand whenever a new variant of the + * Image for an additional zoom is required. Depending on the OS specific implementation + * these calls will be done during the instantiation or later when a new variant is + * requested. + * + * @param device the device on which to create the image + * @param imageGcDrawer the ImageGcDrawer object to be called when a new image variant + * for another zoom is required. + * @param width the width of the new image in points + * @param height the height of the new image in points + * + * @exception IllegalArgumentException + * @since 3.129 + */ +public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { + super(device); + if (imageGcDrawer == null) { + SWT.error(SWT.ERROR_NULL_ARGUMENT); + } + this.imageGcDrawer = imageGcDrawer; + currentDeviceZoom = DPIUtil.getDeviceZoom(); + ImageData imageData = drawWithImageGcDrawer(width, height, currentDeviceZoom); + init (imageData); + init (); +} + /** * Refreshes the image for the current device scale factor. *

@@ -722,6 +759,17 @@ boolean refreshImageForZoom () { refreshed = true; currentDeviceZoom = deviceZoomLevel; } + } else if (imageGcDrawer != null) { + int deviceZoomLevel = deviceZoom; + if (deviceZoomLevel != currentDeviceZoom) { + ImageData data = drawWithImageGcDrawer(width, height, deviceZoomLevel); + /* Release current native resources */ + destroy (); + init(data); + init(); + refreshed = true; + currentDeviceZoom = deviceZoomLevel; + } } else { if (!DPIUtil.useCairoAutoScale()) { int deviceZoomLevel = deviceZoom; @@ -904,6 +952,9 @@ public boolean equals (Object object) { return (styleFlag == image.styleFlag) && imageDataProvider.equals (image.imageDataProvider); } else if (imageFileNameProvider != null && image.imageFileNameProvider != null) { return (styleFlag == image.styleFlag) && imageFileNameProvider.equals (image.imageFileNameProvider); + } else if (imageGcDrawer != null && image.imageGcDrawer != null) { + return styleFlag == image.styleFlag && imageGcDrawer.equals(image.imageGcDrawer) && width == image.width + && height == image.height; } else { return surface == image.surface; } @@ -1110,11 +1161,27 @@ public ImageData getImageData (int zoom) { } else if (imageFileNameProvider != null) { ElementAtZoom fileName = DPIUtil.validateAndGetImagePathAtZoom (imageFileNameProvider, zoom); return DPIUtil.scaleImageData (device, new ImageData (fileName.element()), zoom, fileName.zoom()); + } else if (imageGcDrawer != null) { + return drawWithImageGcDrawer(width, height, zoom); } else { return DPIUtil.scaleImageData (device, getImageDataAtCurrentZoom (), zoom, currentDeviceZoom); } } +private ImageData drawWithImageGcDrawer(int width, int height, int zoom) { + Image image = new Image(device, width, height); + GC gc = new GC(image); + try { + imageGcDrawer.drawOn(gc, width, height); + ImageData imageData = image.getImageData(zoom); + imageGcDrawer.postProcess(imageData); + return imageData; + } finally { + gc.dispose(); + image.dispose(); + } +} + /** * Invokes platform specific functionality to allocate a new image. *

@@ -1179,6 +1246,8 @@ public int hashCode () { return imageDataProvider.hashCode(); } else if (imageFileNameProvider != null) { return imageFileNameProvider.hashCode(); + } else if (imageGcDrawer != null) { + return Objects.hash(imageGcDrawer, width, height); } else { return (int)surface; } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java index ddd2aaeaee3..c27378b60da 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java @@ -172,8 +172,13 @@ private Image (Device device, int nativeZoom) { * @see #dispose() */ public Image(Device device, int width, int height) { + this(device, width, height, DPIUtil.getNativeDeviceZoom()); +} + + +private Image(Device device, int width, int height, int nativeZoom) { super(device); - initialNativeZoom = DPIUtil.getNativeDeviceZoom(); + initialNativeZoom = nativeZoom; final int zoom = getZoom(); width = DPIUtil.scaleUp (width, zoom); height = DPIUtil.scaleUp (height, zoom); @@ -602,6 +607,31 @@ public Image(Device device, ImageDataProvider imageDataProvider) { this.device.registerResourceWithZoomSupport(this); } +/** + * The provided ImageGcDrawer will be called on demand whenever a new variant of the + * Image for an additional zoom is required. Depending on the OS-specific implementation + * these calls will be done during the instantiation or later when a new variant is + * requested. + * + * @param device the device on which to create the image + * @param imageGcDrawer the ImageGcDrawer object to be called when a new image variant + * for another zoom is required. + * @param width the width of the new image in points + * @param height the height of the new image in points + * + * @exception IllegalArgumentException

+ * @since 3.129 + */ +public Image(Device device, ImageGcDrawer imageGcDrawer, int width, int height) { + super(device); + this.imageProvider = new ImageGcDrawerWrapper(imageGcDrawer, width, height); + initialNativeZoom = DPIUtil.getNativeDeviceZoom(); + init(); +} + private ImageData adaptImageDataIfDisabledOrGray(ImageData data) { ImageData returnImageData = null; switch (this.styleFlag) { @@ -1140,6 +1170,9 @@ ImageHandle initNative(String filename, int zoom) { void destroy () { device.deregisterResourceWithZoomSupport(this); if (memGC != null) memGC.dispose(); + if (this.imageProvider != null) { + this.imageProvider.destroy(); + } destroyHandle(); memGC = null; } @@ -1282,14 +1315,17 @@ public Rectangle getBounds() { Rectangle getBounds(int zoom) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); - ImageHandle imageMetadata; if (zoomLevelToImageHandle.containsKey(zoom)) { - imageMetadata = zoomLevelToImageHandle.get(zoom); + ImageHandle imageMetadata = zoomLevelToImageHandle.get(zoom); + Rectangle rectangle = new Rectangle(0, 0, imageMetadata.width, imageMetadata.height); + return DPIUtil.scaleBounds(rectangle, zoom, imageMetadata.zoom); + } else if (this.imageProvider != null) { + return this.imageProvider.getBounds(zoom); } else { - imageMetadata = zoomLevelToImageHandle.values().iterator().next(); + ImageHandle imageMetadata = zoomLevelToImageHandle.values().iterator().next(); + Rectangle rectangle = new Rectangle(0, 0, imageMetadata.width, imageMetadata.height); + return DPIUtil.scaleBounds(rectangle, zoom, imageMetadata.zoom); } - Rectangle rectangle = new Rectangle(0, 0, imageMetadata.width, imageMetadata.height); - return DPIUtil.scaleBounds(rectangle, zoom, imageMetadata.zoom); } /** @@ -1932,6 +1968,9 @@ public void internal_dispose_GC (long hDC, GCData data) { */ @Override public boolean isDisposed() { + if (this.imageProvider != null) { + return this.imageProvider.isDisposed(); + } return zoomLevelToImageHandle.isEmpty(); } @@ -2043,9 +2082,11 @@ public static Image win32_new(Device device, int type, long handle, int nativeZo private abstract class AbstractImageProviderWrapper { abstract Object getProvider(); + protected abstract Rectangle getBounds(int zoom); abstract ImageData getImageData(int zoom); abstract ImageHandle getImageMetadata(int zoom); abstract AbstractImageProviderWrapper createCopy(Image image); + abstract boolean isDisposed(); protected void checkProvider(Object provider, Class expectedClass) { if (provider == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); @@ -2062,6 +2103,9 @@ public boolean equals(Object otherProvider) { return otherProvider instanceof AbstractImageProviderWrapper aip // && getProvider().equals(aip.getProvider()); } + + protected void destroy() { + } } private class ImageFileNameProviderWrapper extends AbstractImageProviderWrapper { @@ -2076,6 +2120,13 @@ private class ImageFileNameProviderWrapper extends AbstractImageProviderWrapper this.provider = provider; } + @Override + protected Rectangle getBounds(int zoom) { + ImageHandle imageHandle = zoomLevelToImageHandle.values().iterator().next(); + Rectangle rectangle = new Rectangle(0, 0, imageHandle.width, imageHandle.height); + return DPIUtil.scaleBounds(rectangle, zoom, imageHandle.zoom); + } + @Override ImageData getImageData(int zoom) { ElementAtZoom fileName = DPIUtil.validateAndGetImagePathAtZoom (provider, zoom); @@ -2099,6 +2150,11 @@ ImageHandle getImageMetadata(int zoom) { return zoomLevelToImageHandle.get(zoom); } + @Override + boolean isDisposed() { + return zoomLevelToImageHandle.isEmpty(); + } + @Override Object getProvider() { return provider; @@ -2127,6 +2183,13 @@ private class ImageDataProviderWrapper extends AbstractImageProviderWrapper { this.provider = provider; } + @Override + protected Rectangle getBounds(int zoom) { + ElementAtZoom data = DPIUtil.validateAndGetImageDataAtZoom (provider, zoom); + Rectangle rectangle = new Rectangle(0, 0, data.element().width, data.element().height); + return DPIUtil.scaleBounds(rectangle, zoom, data.zoom()); + } + @Override ImageData getImageData(int zoom) { ElementAtZoom data = DPIUtil.validateAndGetImageDataAtZoom (provider, zoom); @@ -2143,6 +2206,11 @@ ImageHandle getImageMetadata(int zoom) { return zoomLevelToImageHandle.get(zoom); } + @Override + boolean isDisposed() { + return zoomLevelToImageHandle.isEmpty(); + } + @Override Object getProvider() { return provider; @@ -2154,6 +2222,81 @@ ImageDataProviderWrapper createCopy(Image image) { } } +private class ImageGcDrawerWrapper extends AbstractImageProviderWrapper { + private ImageGcDrawer drawer; + private int width; + private int height; + private boolean isDestroyed; + + public ImageGcDrawerWrapper(ImageGcDrawer imageGcDrawer, int width, int height) { + checkProvider(imageGcDrawer, ImageGcDrawer.class); + this.drawer = imageGcDrawer; + this.width = width; + this.height = height; + } + + @Override + protected Rectangle getBounds(int zoom) { + Rectangle rectangle = new Rectangle(0, 0, width, height); + return DPIUtil.scaleBounds(rectangle, zoom, 100); + } + + @Override + ImageData getImageData(int zoom) { + return getImageMetadata(zoom).getImageData(); + } + + @Override + ImageHandle getImageMetadata(int zoom) { + initialNativeZoom = zoom; + Image image = new Image(device, width, height, zoom); + GC gc = new GC(image); + try { + gc.data.nativeZoom = zoom; + drawer.drawOn(gc, width, height); + ImageData imageData = image.getImageMetadata(zoom).getImageData(); + drawer.postProcess(imageData); + ImageData newData = adaptImageDataIfDisabledOrGray(imageData); + init(newData, zoom); + } finally { + gc.dispose(); + image.dispose(); + } + return zoomLevelToImageHandle.get(zoom); + } + + @Override + protected void destroy() { + isDestroyed = true; + } + + @Override + boolean isDisposed() { + return isDestroyed; + } + + @Override + Object getProvider() { + return drawer; + } + + @Override + ImageGcDrawerWrapper createCopy(Image image) { + return image.new ImageGcDrawerWrapper(drawer, width, height); + } + + @Override + public int hashCode() { + return Objects.hash(getProvider().hashCode(), width, height); + } + + @Override + public boolean equals(Object otherProvider) { + return otherProvider instanceof ImageGcDrawerWrapper aip && getProvider().equals(aip.getProvider()) + && width == aip.width && height == aip.height; + } +} + private class ImageHandle { private final long handle; private final int zoom; diff --git a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet367.java b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet367.java index d808c867fdd..4133afb1516 100644 --- a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet367.java +++ b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet367.java @@ -60,6 +60,10 @@ public static void main (String [] args) { return null; } }; + final ImageGcDrawer imageGcDrawer = gc -> { + gc.drawRectangle(1, 1, 18, 18); + gc.drawLine(3, 3, 17, 17); + }; final Display display = new Display (); final Shell shell = new Shell (display); @@ -98,6 +102,10 @@ public static void main (String [] args) { new Label (shell, SWT.NONE).setImage (new Image (display, imageDataProvider)); new Button(shell, SWT.NONE).setImage (new Image (display, imageDataProvider)); + new Label (shell, SWT.NONE).setText ("ImageGcDrawer:"); + new Label (shell, SWT.NONE).setImage (new Image (display, imageGcDrawer, 20, 20)); + new Button(shell, SWT.NONE).setImage (new Image (display, imageGcDrawer, 20, 20)); + createSeparator(shell); new Label (shell, SWT.NONE).setText ("1. Canvas\n(PaintListener)"); diff --git a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java index 8a1b5273577..ff40443deea 100644 --- a/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java +++ b/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet382.java @@ -63,6 +63,14 @@ public static void main (String [] args) { }; final Display display = new Display (); + + final ImageGcDrawer imageGcDrawer = gc -> { + gc.setBackground(display.getSystemColor(SWT.COLOR_RED)); + gc.fillRectangle(0, 0, 16, 16); + gc.setForeground(display.getSystemColor(SWT.COLOR_YELLOW)); + gc.drawRectangle(4, 4, 8, 8); + }; + final Shell shell = new Shell (display); shell.setText("Snippet382"); shell.setLayout (new GridLayout (3, false)); @@ -84,6 +92,10 @@ public void handleEvent(Event e) { final Image disabledImageWithData = new Image (display,imageWithData, SWT.IMAGE_DISABLE); final Image greyImageWithData = new Image (display,imageWithData, SWT.IMAGE_GRAY); + final Image imageWithGcDrawer = new Image (display, imageGcDrawer, 16, 16); + final Image disabledImageWithGcDrawer = new Image (display, imageWithGcDrawer, SWT.IMAGE_DISABLE); + final Image greyImageWithGcDrawer = new Image (display, imageWithGcDrawer, SWT.IMAGE_GRAY); + try { drawImages(mainGC, gcData, "Normal",40, imageWithFileNameProvider); drawImages(mainGC, gcData, "Disabled",80, disabledImageWithFileNameProvider); @@ -96,6 +108,10 @@ public void handleEvent(Event e) { drawImages(mainGC, gcData, "Normal",280, imageWithDataProvider); drawImages(mainGC, gcData, "Disabled",320, disabledImageWithData); drawImages(mainGC, gcData, "Greyed",360, greyImageWithData); + + drawImages(mainGC, gcData, "Normal", 400, imageWithGcDrawer); + drawImages(mainGC, gcData, "Disabled", 440, disabledImageWithGcDrawer); + drawImages(mainGC, gcData, "Greyed", 480, greyImageWithGcDrawer); } finally { mainGC.dispose (); } @@ -114,7 +130,7 @@ private void drawImages(GC mainGC, GCData gcData, String text, int y, final Imag }; shell.addListener(SWT.Paint, l); - shell.setSize(400, 500); + shell.setSize(400, 550); shell.open (); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java index 7e21ea728af..a9fbb03aef0 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_graphics_Image.java @@ -37,6 +37,7 @@ import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.ImageDataProvider; import org.eclipse.swt.graphics.ImageFileNameProvider; +import org.eclipse.swt.graphics.ImageGcDrawer; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; @@ -97,6 +98,7 @@ public class Test_org_eclipse_swt_graphics_Image { } return new ImageData(getPath(fileName)); }; +ImageGcDrawer imageGcDrawer = (gc, width, height) -> {}; @Before public void setUp() { @@ -607,6 +609,23 @@ public void test_ConstructorLorg_eclipse_swt_graphics_Device_ImageDataProvider() image.dispose(); } +@Test +public void test_ConstructorLorg_eclipse_swt_graphics_Device_ImageGcDrawer() { + // Null provider + ImageGcDrawer drawer = null; + try { + Image image = new Image(display, drawer, 20, 20); + image.dispose(); + fail("No exception thrown for ImageGcDrawer == null"); + } catch (IllegalArgumentException e) { + assertSWTProblem("Incorrect exception thrown for ImageGcDrawer == null", SWT.ERROR_NULL_ARGUMENT, e); + } + + // Valid provider + Image image = new Image(display, imageGcDrawer, 20, 20); + image.dispose(); +} + @Test public void test_equalsLjava_lang_Object() { Image image = null; @@ -675,6 +694,22 @@ public void test_equalsLjava_lang_Object() { image.dispose(); image1.dispose(); } + + // ImageGcDrawer + try { + image = new Image(display, imageGcDrawer, 10, 10); + image1 = image; + + assertFalse(image.equals(null)); + + assertTrue(image.equals(image1)); + + image1 = new Image(display, imageGcDrawer, 10, 10); + assertTrue(image.equals(image1)); + } finally { + image.dispose(); + image1.dispose(); + } } @Test @@ -760,6 +795,13 @@ public void test_getBoundsInPixels() { bounds = image.getBounds(); image.dispose(); assertEquals(":d: Image.getBoundsInPixels method doesn't return bounds in Pixel values.", boundsInPixels, DPIUtil.autoScaleUp(bounds)); + + // create image with ImageGcDrawer + image = new Image(display, imageGcDrawer, bounds.width, bounds.height); + boundsInPixels = image.getBoundsInPixels(); + bounds = image.getBounds(); + image.dispose(); + assertEquals("Image.getBoundsInPixels method doesn't return bounds in Pixel values for ImageGcDrawer.", boundsInPixels, DPIUtil.autoScaleUp(bounds)); } @SuppressWarnings("deprecation") @@ -968,6 +1010,16 @@ public void test_hashCode() { image.dispose(); image1.dispose(); } + + // ImageGcDrawer + try { + image = new Image(display, imageGcDrawer, 10, 10); + image1 = new Image(display, imageGcDrawer, 10, 10); + assertEquals(image1.hashCode(), image.hashCode()); + } finally { + image.dispose(); + image1.dispose(); + } } @Test