From 7403c743ac530c089d3853ed8ea424d8ce4b7c4d Mon Sep 17 00:00:00 2001 From: Amartya Parijat Date: Thu, 2 Jan 2025 12:11:43 +0100 Subject: [PATCH] Refactor out CoordinateSystemMapper from Display and add tests This commit refactors the Display to separate single zoom and multi zoom coordinate system mappers in separate classes. Additionally, it adds some tests for validating the multi-zoom coordinate system mapper. A few tests are disabled because of the current state of multi-zoom coordinate system limitations. Contributes to #62 and #127 --- .../widgets/CoordinateSystemMapperTests.java | 160 +++++++++ .../swt/widgets/CoordinateSystemMapper.java | 41 +++ .../org/eclipse/swt/widgets/Display.java | 305 +----------------- .../MultiZoomCoordinateSystemMapper.java | 265 +++++++++++++++ .../SingleZoomCoordinateSystemMapper.java | 108 +++++++ 5 files changed, 576 insertions(+), 303 deletions(-) create mode 100644 bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/CoordinateSystemMapper.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MultiZoomCoordinateSystemMapper.java create mode 100644 bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/SingleZoomCoordinateSystemMapper.java 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