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..4a8f3fdccbe 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,24 @@ 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 Rectangle imageBounds = new Rectangle(0, 0, size.x - trim.width, size.y - trim.height); + Color transColor = renderer.parent.getBackground(); + final ImageGcDrawer imageGcDrawer = new TransparancyColorImageGcDrawer(transColor) { + @Override + public void drawOn(GC gc) { + gc.setBackground(transColor); + gc.fillRectangle(imageBounds); + renderer.draw(button, SWT.NONE, new Rectangle(trim.x, trim.y, size.x, size.y), gc); + } + }; + return new Image(display, imageGcDrawer, imageBounds.width, imageBounds.height); } 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..b1d1c8b26ec 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 @@ -135,6 +135,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 +389,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 +849,62 @@ 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 (); + ImageData data2x = drawWithImageGcDrawer(imageGcDrawer, width, height, 200); + if (data2x != null) { + alphaInfo_200 = new AlphaInfo(); + NSBitmapImageRep rep = createRepresentation (data2x, alphaInfo_200); + handle.addRepresentation(rep); + rep.release(); + } + } 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); + 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 +1183,8 @@ 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); } else { return handle == image.handle; } @@ -1357,6 +1421,8 @@ public int hashCode () { return imageDataProvider.hashCode(); } else if (imageFileNameProvider != null) { return imageFileNameProvider.hashCode(); + } else if (imageGcDrawer != null) { + return imageGcDrawer.hashCode(); } 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..581ed5dc7c2 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/ImageGcDrawer.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * 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 private logic that draws + * on the empty GC on demand. + * + * @since 3.129 + */ +public interface ImageGcDrawer { + + + /** + * Provides a GC to draw on for a requested zoom level. + *

+ * + * @param gc + * The GC will draw on the underlying Image and is configured for the targeted zoom + * @since 3.129 + */ + void drawOn(GC gc); + + /** + * Implement this method if any post processing of the ImageData created by the operations on the + * GC in drawOn is necessary. + *

+ * + * @param imageData + * The resulting ImageData after drawOn was called + * @since 3.129 + */ + default void postProcess(ImageData imageData) {} +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/TransparancyColorImageGcDrawer.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/TransparancyColorImageGcDrawer.java new file mode 100644 index 00000000000..f054c6d9677 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/TransparancyColorImageGcDrawer.java @@ -0,0 +1,18 @@ +package org.eclipse.swt.internal; + +import org.eclipse.swt.graphics.*; + +public abstract class TransparancyColorImageGcDrawer implements ImageGcDrawer { + + private final Color transparancyColor; + + public TransparancyColorImageGcDrawer(Color transparancyColor) { + this.transparancyColor = transparancyColor; + } + + @Override + public void postProcess(ImageData imageData) { + imageData.transparentPixel = imageData.palette.getPixel(transparancyColor.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..1ea53b07701 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 @@ -151,6 +151,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 +268,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 +667,37 @@ 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,8 @@ 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); } else { return surface == image.surface; } @@ -1110,11 +1160,33 @@ 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) { + if (this.imageGcDrawer != null) { + Image image = new Image(device, width, height); + GC gc = new GC(image); + try { + imageGcDrawer.drawOn(gc); + ImageData imageData = image.getImageData(zoom); + imageGcDrawer.postProcess(imageData); + return imageData; + } finally { + gc.dispose(); + image.dispose(); + } + } + SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, ": ImageGcDrawer [" + imageGcDrawer + "] is null."); + return null; +} + /** * Invokes platform specific functionality to allocate a new image. *

@@ -1179,6 +1251,8 @@ public int hashCode () { return imageDataProvider.hashCode(); } else if (imageFileNameProvider != null) { return imageFileNameProvider.hashCode(); + } else if (imageGcDrawer != null) { + return imageGcDrawer.hashCode(); } 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..3d5a8a9d8a3 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,32 @@ 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 +1171,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 +1316,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 +1969,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 +2083,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 +2104,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 +2121,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 +2151,11 @@ ImageHandle getImageMetadata(int zoom) { return zoomLevelToImageHandle.get(zoom); } + @Override + boolean isDisposed() { + return zoomLevelToImageHandle.isEmpty(); + } + @Override Object getProvider() { return provider; @@ -2127,6 +2184,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 +2207,11 @@ ImageHandle getImageMetadata(int zoom) { return zoomLevelToImageHandle.get(zoom); } + @Override + boolean isDisposed() { + return zoomLevelToImageHandle.isEmpty(); + } + @Override Object getProvider() { return provider; @@ -2154,6 +2223,70 @@ ImageDataProviderWrapper createCopy(Image image) { } } +private class ImageGcDrawerWrapper extends AbstractImageProviderWrapper { + private ImageGcDrawer drawer; + private int width; + private int height; + private boolean isDestroyed = false; + + 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); + 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); + } +} + 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..6653625d88f 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 (); } 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..ac26bb45f14 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 -> {}; @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(); } + + // ImageDataProvider + try { + image = new Image(display, imageGcDrawer, 10, 10); + image1 = image; + + assertFalse(":g:", image.equals(null)); + + assertTrue(":h:", image.equals(image1)); + + image1 = new Image(display, imageGcDrawer, 10, 10); + assertTrue(":i:", 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(":d: Image.getBoundsInPixels method doesn't return bounds in Pixel values.", 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(":d:", image1.hashCode(), image.hashCode()); + } finally { + image.dispose(); + image1.dispose(); + } } @Test