diff --git a/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java new file mode 100644 index 00000000000..75101e16228 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta Solutions 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 Solutions - initial tests + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.function.*; +import java.util.stream.*; + +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.*; +import org.junit.jupiter.api.*; +import org.junit.jupiter.params.*; +import org.junit.jupiter.params.provider.*; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class CoordinateSystemMapperTests { + + Supplier getMonitorConsumer; + Monitor[] monitors; + + private Monitor createMonitor(CoordinateSystemMapper mapper, Rectangle boundsInPixels, int nativeZoom) { + Monitor monitor = new Monitor(); + Rectangle bounds = mapper.mapMonitorBounds(boundsInPixels, DPIUtil.getZoomForAutoscaleProperty(nativeZoom)); + monitor.setBounds(bounds); + monitor.setClientArea(bounds); + monitor.zoom = nativeZoom; + return monitor; + } + + void setupMonitors(CoordinateSystemMapper mapper) { + Rectangle boundsInPixelsForLeftMonitor = new Rectangle(0, 0, 2000, 2000); + Rectangle boundsInPixelsForRightMonitor = new Rectangle(2000, 0, 2000, 2000); + monitors = new Monitor[] { createMonitor(mapper, boundsInPixelsForLeftMonitor, 200), + createMonitor(mapper, boundsInPixelsForRightMonitor, 100) }; + } + + Stream provideCoordinateSystemMappers() { + return Stream.of(new MultiZoomCoordinateSystemMapper(null, () -> monitors), + new SingleZoomCoordinateSystemMapper(null)); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + void translatePointInNoMonitorBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Point pt = new Point(5000, -400); + Point px = mapper.translateToDisplayCoordinates(pt, monitors[0].getZoom()); + assertEquals(pt, mapper.translateFromDisplayCoordinates(px, monitors[0].getZoom())); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") + void translatePointInGapBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Point pt = new Point(1900, 400); + Point px = mapper.translateToDisplayCoordinates(pt, monitors[0].getZoom()); + assertEquals(pt, mapper.translateFromDisplayCoordinates(px, monitors[0].getZoom())); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + void translateRectangleInNoMonitorBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Rectangle rectInPts = new Rectangle(5000, -400, 200, 200); + Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); + assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") + void translateRectangleInGapBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Rectangle rectInPts = new Rectangle(1800, 400, 100, 100); + Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); + assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") + void translateRectangleInGapPartiallyInRightBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Rectangle rectInPts = new Rectangle(1950, 400, 100, 100); + Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); + assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + void translateRectangleInGapPartiallyInLeftBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Rectangle rectInPts = new Rectangle(750, 400, 100, 100); + Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); + assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + void translateRectangleInPointsInBothMonitorsPartiallyBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Rectangle rectInPts = new Rectangle(950, 400, 1500, 100); + Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()); + assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom())); + } + + @Test + @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") + void moveRectangleInPixelsInRightMonitorsPartiallyBackAndForthShouldBeTheSame() { + CoordinateSystemMapper mapper = provideCoordinateSystemMappers().findFirst().get(); + setupMonitors(mapper); + Rectangle rectInPxs = new Rectangle(1990, -10, 2000, 2000); + Rectangle expectedSmallRectInPxs = new Rectangle(0, 0, 0, monitors[0].getZoom()); + expectedSmallRectInPxs.x = rectInPxs.x + (rectInPxs.width / 2) - 200; + expectedSmallRectInPxs.y = rectInPxs.y + (rectInPxs.height / 2) - 200; + expectedSmallRectInPxs.width = 400; + expectedSmallRectInPxs.height = 400; + Rectangle rectInPts = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()); + Rectangle smallRectInPts = new Rectangle(0, 0, 0, monitors[0].getZoom()); + smallRectInPts.x = rectInPts.x + (rectInPts.width / 2) - 200; + smallRectInPts.y = rectInPts.y + (rectInPts.height / 2) - 200; + smallRectInPts.width = 400; + smallRectInPts.height = 400; + Rectangle smallRectInPxs = mapper.translateToDisplayCoordinates(smallRectInPts, monitors[0].getZoom()); + assertEquals(expectedSmallRectInPxs, smallRectInPxs); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + @Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper") + void translateRectangleInPixelsOutisdeMonitorsBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Rectangle rectInPxs = new Rectangle(4400, 400, 1000, 1000); + Rectangle rectInPts = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()); + assertEquals(rectInPxs, mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom())); + } + + @ParameterizedTest + @MethodSource("provideCoordinateSystemMappers") + void translateRectangleInPixelsInBothMonitorsBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) { + setupMonitors(mapper); + Rectangle rectInPxs = new Rectangle(1500, 400, 502, 500); + Rectangle rectInPts = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()); + assertEquals(rectInPxs, mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom())); + } + +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoordinateSystemMapper.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoordinateSystemMapper.java new file mode 100644 index 00000000000..28527ed39e4 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoordinateSystemMapper.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta Solutions 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 Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.graphics.*; + +interface CoordinateSystemMapper { + + Rectangle map(Control from, Control to, Rectangle rectangle); + + Rectangle map(Control from, Control to, int x, int y, int width, int height); + + Point map(Control from, Control to, Point point); + + Point map(Control from, Control to, int x, int y); + + Rectangle mapMonitorBounds(Rectangle rectangle, int zoom); + + Point translateFromDisplayCoordinates(Point point, int zoom); + + Point translateToDisplayCoordinates(Point point, int zoom); + + Rectangle translateFromDisplayCoordinates(Rectangle rect, int zoom); + + Rectangle translateToDisplayCoordinates(Rectangle rect, int zoom); + + void setCursorLocation(int x, int y); + + Point getCursorLocation(); +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java index 70576d85cea..700c90e3721 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Display.java @@ -2773,7 +2773,7 @@ protected void init () { controlByHandle = new HashMap<>(); this.synchronizer = new Synchronizer (this); if (this.coordinateSystemMapper == null) { - this.coordinateSystemMapper = new SingleZoomCoordinateSystemMapper(); + this.coordinateSystemMapper = new SingleZoomCoordinateSystemMapper(this); } super.init (); DPIUtil.setDeviceZoom (getDeviceZoom ()); @@ -3011,15 +3011,6 @@ Point mapInPixels (Control from, Control to, int x, int y) { return new Point (point.x, point.y); } -private int getZoomLevelForMapping(Control from, Control to) { - if (from != null && from.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT); - if (to != null && to.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT); - if (to != null) { - return to.getZoom(); - } - return from.getZoom(); -} - /** * Maps a point from one coordinate system to another. * When the control is null, coordinates are mapped to @@ -5300,7 +5291,7 @@ public boolean setRescalingAtRuntime(boolean activate) { int desiredApiAwareness = activate ? OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 : OS.DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; if (setDPIAwareness(desiredApiAwareness)) { rescalingAtRuntime = activate; - coordinateSystemMapper = activate ? new MultiZoomCoordinateSystemMapper() : new SingleZoomCoordinateSystemMapper(); + coordinateSystemMapper = activate ? new MultiZoomCoordinateSystemMapper(this, this::getMonitors) : new SingleZoomCoordinateSystemMapper(this); // dispose a existing font registry for the default display SWTFontProvider.disposeFontRegistry(this); return true; @@ -5332,296 +5323,4 @@ private boolean setDPIAwareness(int desiredDpiAwareness) { return true; } -private interface CoordinateSystemMapper { - - Rectangle map(Control from, Control to, Rectangle rectangle); - - Rectangle map(Control from, Control to, int x, int y, int width, int height); - - Point map(Control from, Control to, Point point); - - Point map(Control from, Control to, int x, int y); - - Rectangle mapMonitorBounds(Rectangle rectangle, int zoom); - - Point translateFromDisplayCoordinates(Point point, int zoom); - - Point translateToDisplayCoordinates(Point point, int zoom); - - Rectangle translateFromDisplayCoordinates(Rectangle rect, int zoom); - - Rectangle translateToDisplayCoordinates(Rectangle rect, int zoom); - - void setCursorLocation(int x, int y); - - Point getCursorLocation(); - -} - -private class SingleZoomCoordinateSystemMapper implements CoordinateSystemMapper { - @Override - public Point map (Control from, Control to, Point point) { - int zoom = getZoomLevelForMapping(from, to); - point = DPIUtil.scaleUp(point, zoom); - return DPIUtil.scaleDown(mapInPixels(from, to, point), zoom); - } - - @Override - public Rectangle map (Control from, Control to, Rectangle rectangle) { - int zoom = getZoomLevelForMapping(from, to); - rectangle = DPIUtil.scaleUp(rectangle, zoom); - return DPIUtil.scaleDown(mapInPixels(from, to, rectangle), zoom); - } - - @Override - public Point map (Control from, Control to, int x, int y) { - int zoom = getZoomLevelForMapping(from, to); - x = DPIUtil.scaleUp(x, zoom); - y = DPIUtil.scaleUp(y, zoom); - return DPIUtil.scaleDown(mapInPixels(from, to, x, y), zoom); - } - - @Override - public Rectangle map (Control from, Control to, int x, int y, int width, int height) { - int zoom = getZoomLevelForMapping(from, to); - x = DPIUtil.scaleUp(x, zoom); - y = DPIUtil.scaleUp(y, zoom); - width = DPIUtil.scaleUp(width, zoom); - height = DPIUtil.scaleUp(height, zoom); - return DPIUtil.scaleDown(mapInPixels(from, to, x, y, width, height), zoom); - } - - @Override - public Rectangle mapMonitorBounds(Rectangle rect, int zoom) { - return DPIUtil.autoScaleDown(rect); - } - - @Override - public Point translateFromDisplayCoordinates(Point point, int zoom) { - return DPIUtil.scaleDown(point, zoom); - } - - @Override - public Point translateToDisplayCoordinates(Point point, int zoom) { - return DPIUtil.scaleUp(point, zoom); - } - - @Override - public Rectangle translateFromDisplayCoordinates(Rectangle rect, int zoom) { - return DPIUtil.scaleDown(rect, zoom); - } - - @Override - public Rectangle translateToDisplayCoordinates(Rectangle rect, int zoom) { - return DPIUtil.scaleUp(rect, zoom); - } - - @Override - public Point getCursorLocation () { - Point cursorLocationInPixels = getCursorLocationInPixels(); - return DPIUtil.autoScaleDown(cursorLocationInPixels); - } - - @Override - public void setCursorLocation (int x, int y) { - setCursorLocationInPixels (DPIUtil.autoScaleUp (x), DPIUtil.autoScaleUp (y)); - } -} - -private class MultiZoomCoordinateSystemMapper implements CoordinateSystemMapper { - @Override - public Point map (Control from, Control to, Point point) { - return map(from, to, point.x, point.y); - } - - @Override - public Rectangle map (Control from, Control to, Rectangle rectangle) { - return map(from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height); - } - - @Override - public Point map (Control from, Control to, int x, int y) { - Point mappedPointInPoints; - if (from == null) { - Point mappedPointInpixels = mapInPixels(from, to, getPixelsFromPoint(to.getShell().getMonitor(), x, y)); - mappedPointInPoints = DPIUtil.scaleDown(mappedPointInpixels, to.getZoom()); - } else if (to == null) { - Point mappedPointInpixels = mapInPixels(from, to, DPIUtil.scaleUp(new Point(x, y), from.getZoom())); - mappedPointInPoints = getPointFromPixels(from.getShell().getMonitor(), mappedPointInpixels.x, mappedPointInpixels.y); - } else { - Point mappedPointInpixels = mapInPixels(from, to, DPIUtil.scaleUp(new Point(x, y), from.getZoom())); - mappedPointInPoints = DPIUtil.scaleDown(mappedPointInpixels, to.getZoom()); - } - return mappedPointInPoints; - } - - @Override - public Rectangle map (Control from, Control to, int x, int y, int width, int height) { - Rectangle mappedRectangleInPoints; - if (from == null) { - Rectangle mappedRectangleInPixels = mapInPixels(from, to, translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, to.getShell().getMonitor())); - mappedRectangleInPoints = DPIUtil.scaleDown(mappedRectangleInPixels, to.getZoom()); - } else if (to == null) { - Rectangle mappedRectangleInPixels = mapInPixels(from, to, DPIUtil.scaleUp(new Rectangle(x, y, width, height), from.getZoom())); - mappedRectangleInPoints = translateRectangleInPointsInDisplayCoordinateSystem(mappedRectangleInPixels.x, mappedRectangleInPixels.y, mappedRectangleInPixels.width, mappedRectangleInPixels.height, from.getShell().getMonitor()); - } else { - Rectangle mappedRectangleInPixels = mapInPixels(from, to, DPIUtil.scaleUp(new Rectangle(x, y, width, height), from.getZoom())); - mappedRectangleInPoints = DPIUtil.scaleDown(mappedRectangleInPixels, to.getZoom()); - } - return mappedRectangleInPoints; - } - - @Override - public Rectangle mapMonitorBounds(Rectangle rect, int zoom) { - Rectangle bounds = DPIUtil.scaleDown(rect, zoom); - bounds.x = rect.x; - bounds.y = rect.y; - return bounds; - } - - @Override - public Point translateFromDisplayCoordinates(Point point, int zoom) { - return translateLocationInPixelsFromDisplayCoordinateSystem(point.x, point.y); - } - - @Override - public Point translateToDisplayCoordinates(Point point, int zoom) { - return translateLocationInPointsToDisplayCoordinateSystem(point.x, point.y); - } - - @Override - public Rectangle translateFromDisplayCoordinates(Rectangle rect, int zoom) { - return translateRectangleInPixelsFromDisplayCoordinateSystemByContainment(rect.x, rect.y, rect.width, rect.height); - } - - @Override - public Rectangle translateToDisplayCoordinates(Rectangle rect, int zoom) { - return translateRectangleInPointsToDisplayCoordinateSystemByContainment(rect.x, rect.y, rect.width, rect.height); - } - - @Override - public Point getCursorLocation () { - Point cursorLocationInPixels = getCursorLocationInPixels(); - return translateLocationInPixelsFromDisplayCoordinateSystem(cursorLocationInPixels.x, cursorLocationInPixels.y); - } - - @Override - public void setCursorLocation (int x, int y) { - Point cursorLocationInPixels = translateLocationInPointsToDisplayCoordinateSystem(x, y); - setCursorLocationInPixels (cursorLocationInPixels.x, cursorLocationInPixels.y); - } - - private Point translateLocationInPointsToDisplayCoordinateSystem(int x, int y) { - Monitor monitor = getContainingMonitor(x, y); - return getPixelsFromPoint(monitor, x, y); - } - - private Point translateLocationInPixelsFromDisplayCoordinateSystem(int x, int y) { - Monitor monitor = getContainingMonitorInPixelsCoordinate(x, y); - return getPointFromPixels(monitor, x, y); - } - - private Rectangle translateRectangleInPointsToDisplayCoordinateSystemByContainment(int x, int y, int width, int height) { - Monitor monitorByLocation = getContainingMonitor(x, y); - Monitor monitorByContainment = getContainingMonitor(x, y, width, height); - return translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, monitorByLocation, monitorByContainment); - } - - private Rectangle translateRectangleInPixelsInDisplayCoordinateSystem(int x, int y, int width, int height, Monitor monitor) { - return translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, monitor, monitor); - } - - private Rectangle translateRectangleInPixelsInDisplayCoordinateSystem(int x, int y, int width, int height, Monitor monitorOfLocation, Monitor monitorOfArea) { - Point topLeft = getPixelsFromPoint(monitorOfLocation, x, y); - int zoom = getApplicableMonitorZoom(monitorOfArea); - int widthInPixels = DPIUtil.scaleUp(width, zoom); - int heightInPixels = DPIUtil.scaleUp(height, zoom); - return new Rectangle(topLeft.x, topLeft.y, widthInPixels, heightInPixels); - } - - private Rectangle translateRectangleInPixelsFromDisplayCoordinateSystemByContainment(int x, int y, int widthInPixels, int heightInPixels) { - Monitor monitorByLocation = getContainingMonitor(x, y); - Monitor monitorByContainment = getContainingMonitor(x, y, widthInPixels, heightInPixels); - return translateRectangleInPointsInDisplayCoordinateSystem(x, y, widthInPixels, heightInPixels, monitorByLocation, monitorByContainment); - } - - private Rectangle translateRectangleInPointsInDisplayCoordinateSystem(int x, int y, int widthInPixels, int heightInPixels, Monitor monitor) { - return translateRectangleInPointsInDisplayCoordinateSystem(x, y, widthInPixels, heightInPixels, monitor, monitor); - } - - - private Rectangle translateRectangleInPointsInDisplayCoordinateSystem(int x, int y, int widthInPixels, int heightInPixels, Monitor monitorOfLocation, Monitor monitorOfArea) { - Point topLeft = getPointFromPixels(monitorOfLocation, x, y); - int zoom = getApplicableMonitorZoom(monitorOfArea); - int width = DPIUtil.scaleDown(widthInPixels, zoom); - int height = DPIUtil.scaleDown(heightInPixels, zoom); - return new Rectangle(topLeft.x, topLeft.y, width, height); - } - - private Monitor getContainingMonitor(int x, int y) { - Monitor[] monitors = getMonitors(); - for (Monitor currentMonitor : monitors) { - Rectangle clientArea = currentMonitor.getClientArea(); - if (clientArea.contains(x, y)) { - return currentMonitor; - } - } - return getPrimaryMonitor(); - } - - private Monitor getContainingMonitor(int x, int y, int width, int height) { - Rectangle rectangle = new Rectangle(x, y, width, height); - Monitor[] monitors = getMonitors(); - Monitor selectedMonitor = getPrimaryMonitor(); - int highestArea = 0; - for (Monitor currentMonitor : monitors) { - Rectangle clientArea = currentMonitor.getClientArea(); - Rectangle intersection = clientArea.intersection(rectangle); - int area = intersection.width * intersection.height; - if (area > highestArea) { - selectedMonitor = currentMonitor; - highestArea = area; - } - } - return selectedMonitor; - } - - private Monitor getContainingMonitorInPixelsCoordinate(int xInPixels, int yInPixels) { - Monitor[] monitors = getMonitors(); - for (Monitor current : monitors) { - Rectangle clientArea = getMonitorClientAreaInPixels(current); - if (clientArea.contains(xInPixels, yInPixels)) { - return current; - } - } - return getPrimaryMonitor(); - } - - private Rectangle getMonitorClientAreaInPixels(Monitor monitor) { - int zoom = getApplicableMonitorZoom(monitor); - int widthInPixels = DPIUtil.scaleUp(monitor.clientWidth, zoom); - int heightInPixels = DPIUtil.scaleUp(monitor.clientHeight, zoom); - return new Rectangle(monitor.clientX, monitor.clientY, widthInPixels, heightInPixels); - } - - private Point getPixelsFromPoint(Monitor monitor, int x, int y) { - int zoom = getApplicableMonitorZoom(monitor); - int mappedX = DPIUtil.scaleUp(x - monitor.clientX, zoom) + monitor.clientX; - int mappedY = DPIUtil.scaleUp(y - monitor.clientY, zoom) + monitor.clientY; - return new Point(mappedX, mappedY); - } - - private Point getPointFromPixels(Monitor monitor, int x, int y) { - int zoom = getApplicableMonitorZoom(monitor); - int mappedX = DPIUtil.scaleDown(x - monitor.clientX, zoom) + monitor.clientX; - int mappedY = DPIUtil.scaleDown(y - monitor.clientY, zoom) + monitor.clientY; - return new Point(mappedX, mappedY); - } - - private int getApplicableMonitorZoom(Monitor monitor) { - return DPIUtil.getZoomForAutoscaleProperty(monitor.zoom); - } - -} - } diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MultiZoomCoordinateSystemMapper.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MultiZoomCoordinateSystemMapper.java new file mode 100644 index 00000000000..7c3d8760ceb --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MultiZoomCoordinateSystemMapper.java @@ -0,0 +1,265 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta Solutions 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 Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import java.util.function.*; + +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.*; + +class MultiZoomCoordinateSystemMapper implements CoordinateSystemMapper { + + private final Display display; + + Supplier monitorSupplier; + + private MultiZoomCoordinateSystemMapper(Display display) { + this.display = display; + } + + MultiZoomCoordinateSystemMapper(Display display, Supplier monitorSupplier) { + this(display); + this.monitorSupplier = monitorSupplier; + } + + @Override + public Point map(Control from, Control to, Point point) { + return map(from, to, point.x, point.y); + } + + @Override + public Rectangle map(Control from, Control to, Rectangle rectangle) { + return map(from, to, rectangle.x, rectangle.y, rectangle.width, rectangle.height); + } + + @Override + public Point map(Control from, Control to, int x, int y) { + Point mappedPointInPoints; + if (from == null) { + Point mappedPointInpixels = display.mapInPixels(from, to, + getPixelsFromPoint(to.getShell().getMonitor(), x, y)); + mappedPointInPoints = DPIUtil.scaleDown(mappedPointInpixels, to.getZoom()); + } else if (to == null) { + Point mappedPointInpixels = display.mapInPixels(from, to, DPIUtil.scaleUp(new Point(x, y), from.getZoom())); + mappedPointInPoints = getPointFromPixels(from.getShell().getMonitor(), mappedPointInpixels.x, + mappedPointInpixels.y); + } else { + Point mappedPointInpixels = display.mapInPixels(from, to, DPIUtil.scaleUp(new Point(x, y), from.getZoom())); + mappedPointInPoints = DPIUtil.scaleDown(mappedPointInpixels, to.getZoom()); + } + return mappedPointInPoints; + } + + @Override + public Rectangle map(Control from, Control to, int x, int y, int width, int height) { + Rectangle mappedRectangleInPoints; + if (from == null) { + Rectangle mappedRectangleInPixels = display.mapInPixels(from, to, + translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, + to.getShell().getMonitor())); + mappedRectangleInPoints = DPIUtil.scaleDown(mappedRectangleInPixels, to.getZoom()); + } else if (to == null) { + Rectangle mappedRectangleInPixels = display.mapInPixels(from, to, + DPIUtil.scaleUp(new Rectangle(x, y, width, height), from.getZoom())); + mappedRectangleInPoints = translateRectangleInPointsInDisplayCoordinateSystem(mappedRectangleInPixels.x, + mappedRectangleInPixels.y, mappedRectangleInPixels.width, mappedRectangleInPixels.height, + from.getShell().getMonitor()); + } else { + Rectangle mappedRectangleInPixels = display.mapInPixels(from, to, + DPIUtil.scaleUp(new Rectangle(x, y, width, height), from.getZoom())); + mappedRectangleInPoints = DPIUtil.scaleDown(mappedRectangleInPixels, to.getZoom()); + } + return mappedRectangleInPoints; + } + + @Override + public Rectangle mapMonitorBounds(Rectangle rect, int zoom) { + Rectangle bounds = DPIUtil.scaleDown(rect, zoom); + bounds.x = rect.x; + bounds.y = rect.y; + return bounds; + } + + @Override + public Point translateFromDisplayCoordinates(Point point, int zoom) { + return translateLocationInPixelsFromDisplayCoordinateSystem(point.x, point.y); + } + + @Override + public Point translateToDisplayCoordinates(Point point, int zoom) { + return translateLocationInPointsToDisplayCoordinateSystem(point.x, point.y); + } + + @Override + public Rectangle translateFromDisplayCoordinates(Rectangle rect, int zoom) { + return translateRectangleInPixelsFromDisplayCoordinateSystemByContainment(rect.x, rect.y, rect.width, + rect.height); + } + + @Override + public Rectangle translateToDisplayCoordinates(Rectangle rect, int zoom) { + return translateRectangleInPointsToDisplayCoordinateSystemByContainment(rect.x, rect.y, rect.width, + rect.height); + } + + @Override + public Point getCursorLocation() { + Point cursorLocationInPixels = display.getCursorLocationInPixels(); + return translateLocationInPixelsFromDisplayCoordinateSystem(cursorLocationInPixels.x, cursorLocationInPixels.y); + } + + @Override + public void setCursorLocation(int x, int y) { + Point cursorLocationInPixels = translateLocationInPointsToDisplayCoordinateSystem(x, y); + display.setCursorLocationInPixels(cursorLocationInPixels.x, cursorLocationInPixels.y); + } + + private Point translateLocationInPointsToDisplayCoordinateSystem(int x, int y) { + Monitor monitor = getContainingMonitor(x, y); + return getPixelsFromPoint(monitor, x, y); + } + + private Point translateLocationInPixelsFromDisplayCoordinateSystem(int x, int y) { + Monitor monitor = getContainingMonitorInPixelsCoordinate(x, y); + return getPointFromPixels(monitor, x, y); + } + + private Rectangle translateRectangleInPointsToDisplayCoordinateSystemByContainment(int x, int y, int width, + int height) { + Monitor monitorByLocation = getContainingMonitor(x, y); + Monitor monitorByContainment = getContainingMonitor(x, y, width, height); + return translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, monitorByLocation, + monitorByContainment); + } + + private Rectangle translateRectangleInPixelsInDisplayCoordinateSystem(int x, int y, int width, int height, + Monitor monitor) { + return translateRectangleInPixelsInDisplayCoordinateSystem(x, y, width, height, monitor, monitor); + } + + private Rectangle translateRectangleInPixelsInDisplayCoordinateSystem(int x, int y, int width, int height, + Monitor monitorOfLocation, Monitor monitorOfArea) { + Point topLeft = getPixelsFromPoint(monitorOfLocation, x, y); + int zoom = getApplicableMonitorZoom(monitorOfArea); + int widthInPixels = DPIUtil.scaleUp(width, zoom); + int heightInPixels = DPIUtil.scaleUp(height, zoom); + return new Rectangle(topLeft.x, topLeft.y, widthInPixels, heightInPixels); + } + + private Rectangle translateRectangleInPixelsFromDisplayCoordinateSystemByContainment(int x, int y, + int widthInPixels, int heightInPixels) { + Monitor monitorByLocation = getContainingMonitor(x, y); + Monitor monitorByContainment = getContainingMonitorInPixelsCoordinate(x, y, widthInPixels, heightInPixels); + return translateRectangleInPointsInDisplayCoordinateSystem(x, y, widthInPixels, heightInPixels, + monitorByLocation, monitorByContainment); + } + + private Rectangle translateRectangleInPointsInDisplayCoordinateSystem(int x, int y, int widthInPixels, + int heightInPixels, Monitor monitor) { + return translateRectangleInPointsInDisplayCoordinateSystem(x, y, widthInPixels, heightInPixels, monitor, + monitor); + } + + private Rectangle translateRectangleInPointsInDisplayCoordinateSystem(int x, int y, int widthInPixels, + int heightInPixels, Monitor monitorOfLocation, Monitor monitorOfArea) { + Point topLeft = getPointFromPixels(monitorOfLocation, x, y); + int zoom = getApplicableMonitorZoom(monitorOfArea); + int width = DPIUtil.scaleDown(widthInPixels, zoom); + int height = DPIUtil.scaleDown(heightInPixels, zoom); + return new Rectangle(topLeft.x, topLeft.y, width, height); + } + + private Monitor getContainingMonitor(int x, int y) { + Monitor[] monitors = monitorSupplier.get(); + for (Monitor currentMonitor : monitors) { + Rectangle clientArea = currentMonitor.getClientArea(); + if (clientArea.contains(x, y)) { + return currentMonitor; + } + } + return monitors[0]; + } + + private Monitor getContainingMonitor(int x, int y, int width, int height) { + Rectangle rectangle = new Rectangle(x, y, width, height); + Monitor[] monitors = monitorSupplier.get(); + Monitor selectedMonitor = monitors[0]; + int highestArea = 0; + for (Monitor currentMonitor : monitors) { + Rectangle clientArea = currentMonitor.getClientArea(); + Rectangle intersection = clientArea.intersection(rectangle); + int area = intersection.width * intersection.height; + if (area > highestArea) { + selectedMonitor = currentMonitor; + highestArea = area; + } + } + return selectedMonitor; + } + + private Monitor getContainingMonitorInPixelsCoordinate(int xInPixels, int yInPixels) { + Monitor[] monitors = monitorSupplier.get(); + for (Monitor current : monitors) { + Rectangle clientArea = getMonitorClientAreaInPixels(current); + if (clientArea.contains(xInPixels, yInPixels)) { + return current; + } + } + return monitors[0]; + } + + private Monitor getContainingMonitorInPixelsCoordinate(int xInPixels, int yInPixels, int widthInPixels, + int heightInPixels) { + Rectangle rectangle = new Rectangle(xInPixels, yInPixels, widthInPixels, heightInPixels); + Monitor[] monitors = monitorSupplier.get(); + Monitor selectedMonitor = monitors[0]; + int highestArea = 0; + for (Monitor currentMonitor : monitors) { + Rectangle clientArea = getMonitorClientAreaInPixels(currentMonitor); + Rectangle intersection = clientArea.intersection(rectangle); + int area = intersection.width * intersection.height; + if (area > highestArea) { + selectedMonitor = currentMonitor; + highestArea = area; + } + } + return selectedMonitor; + } + + private Rectangle getMonitorClientAreaInPixels(Monitor monitor) { + int zoom = getApplicableMonitorZoom(monitor); + int widthInPixels = DPIUtil.scaleUp(monitor.clientWidth, zoom); + int heightInPixels = DPIUtil.scaleUp(monitor.clientHeight, zoom); + return new Rectangle(monitor.clientX, monitor.clientY, widthInPixels, heightInPixels); + } + + private Point getPixelsFromPoint(Monitor monitor, int x, int y) { + int zoom = getApplicableMonitorZoom(monitor); + int mappedX = DPIUtil.scaleUp(x - monitor.clientX, zoom) + monitor.clientX; + int mappedY = DPIUtil.scaleUp(y - monitor.clientY, zoom) + monitor.clientY; + return new Point(mappedX, mappedY); + } + + private Point getPointFromPixels(Monitor monitor, int x, int y) { + int zoom = getApplicableMonitorZoom(monitor); + int mappedX = DPIUtil.scaleDown(x - monitor.clientX, zoom) + monitor.clientX; + int mappedY = DPIUtil.scaleDown(y - monitor.clientY, zoom) + monitor.clientY; + return new Point(mappedX, mappedY); + } + + private int getApplicableMonitorZoom(Monitor monitor) { + return DPIUtil.getZoomForAutoscaleProperty(monitor.zoom); + } + +} \ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/SingleZoomCoordinateSystemMapper.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/SingleZoomCoordinateSystemMapper.java new file mode 100644 index 00000000000..84ae1fb64f7 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/SingleZoomCoordinateSystemMapper.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2025 Yatta Solutions 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 Solutions - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.widgets; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; +import org.eclipse.swt.internal.*; + +class SingleZoomCoordinateSystemMapper implements CoordinateSystemMapper { + + private final Display display; + + SingleZoomCoordinateSystemMapper(Display display) { + this.display = display; + } + + private int getZoomLevelForMapping(Control from, Control to) { + if (from != null && from.isDisposed()) { + display.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (to != null && to.isDisposed()) { + display.error(SWT.ERROR_INVALID_ARGUMENT); + } + if (to != null) { + return to.getZoom(); + } + return from.getZoom(); + } + + @Override + public Point map(Control from, Control to, Point point) { + int zoom = getZoomLevelForMapping(from, to); + point = DPIUtil.scaleUp(point, zoom); + return DPIUtil.scaleDown(display.mapInPixels(from, to, point), zoom); + } + + @Override + public Rectangle map(Control from, Control to, Rectangle rectangle) { + int zoom = getZoomLevelForMapping(from, to); + rectangle = DPIUtil.scaleUp(rectangle, zoom); + return DPIUtil.scaleDown(display.mapInPixels(from, to, rectangle), zoom); + } + + @Override + public Point map(Control from, Control to, int x, int y) { + int zoom = getZoomLevelForMapping(from, to); + x = DPIUtil.scaleUp(x, zoom); + y = DPIUtil.scaleUp(y, zoom); + return DPIUtil.scaleDown(display.mapInPixels(from, to, x, y), zoom); + } + + @Override + public Rectangle map(Control from, Control to, int x, int y, int width, int height) { + int zoom = getZoomLevelForMapping(from, to); + x = DPIUtil.scaleUp(x, zoom); + y = DPIUtil.scaleUp(y, zoom); + width = DPIUtil.scaleUp(width, zoom); + height = DPIUtil.scaleUp(height, zoom); + return DPIUtil.scaleDown(display.mapInPixels(from, to, x, y, width, height), zoom); + } + + @Override + public Rectangle mapMonitorBounds(Rectangle rect, int zoom) { + return DPIUtil.autoScaleDown(rect); + } + + @Override + public Point translateFromDisplayCoordinates(Point point, int zoom) { + return DPIUtil.scaleDown(point, zoom); + } + + @Override + public Point translateToDisplayCoordinates(Point point, int zoom) { + return DPIUtil.scaleUp(point, zoom); + } + + @Override + public Rectangle translateFromDisplayCoordinates(Rectangle rect, int zoom) { + return DPIUtil.scaleDown(rect, zoom); + } + + @Override + public Rectangle translateToDisplayCoordinates(Rectangle rect, int zoom) { + return DPIUtil.scaleUp(rect, zoom); + } + + @Override + public Point getCursorLocation() { + Point cursorLocationInPixels = display.getCursorLocationInPixels(); + return DPIUtil.autoScaleDown(cursorLocationInPixels); + } + + @Override + public void setCursorLocation(int x, int y) { + display.setCursorLocationInPixels(DPIUtil.autoScaleUp(x), DPIUtil.autoScaleUp(y)); + } +} \ No newline at end of file