Skip to content

Commit 880a4dc

Browse files
committed
Use MonitorAware Coordinates in multi zoom
This commit contributes to the use of MonitorAware Points and Rectangles for the translation between points and pixels coordinates in the Display Coordinate System. Since the Display Coordinate System can have different scales (zoom) in different area, it is designed to be not continuous in the points coordinates. Hence when we manipulate the coordinates of a Point or a Rectangle object, it might end up in a region which is between the 2 monitors in the point coordibate system, which we consider a gap. So, we need the context of the monitor on which those points and rectangles were created in the first place to evaluate the scaling factor. If the context is not available or the coordinates were updated to an irrelevant value, a fallback method tries to evaluate the right monitor for the coordinates and evaluates the scaled value with that. contributes to #62 and #127
1 parent d441a95 commit 880a4dc

File tree

6 files changed

+253
-90
lines changed

6 files changed

+253
-90
lines changed

bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/widgets/CoordinateSystemMapperTests.java

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package org.eclipse.swt.widgets;
1515

1616
import static org.junit.jupiter.api.Assertions.assertEquals;
17+
import static org.junit.jupiter.api.Assertions.assertTrue;
1718

1819
import java.util.function.*;
1920
import java.util.stream.*;
@@ -39,16 +40,23 @@ private Monitor createMonitor(CoordinateSystemMapper mapper, Rectangle boundsInP
3940
return monitor;
4041
}
4142

42-
void setupMonitors(CoordinateSystemMapper mapper) {
43+
private void setupMonitors(CoordinateSystemMapper mapper) {
4344
Rectangle boundsInPixelsForLeftMonitor = new Rectangle(0, 0, 2000, 2000);
4445
Rectangle boundsInPixelsForRightMonitor = new Rectangle(2000, 0, 2000, 2000);
4546
monitors = new Monitor[] { createMonitor(mapper, boundsInPixelsForLeftMonitor, 200),
4647
createMonitor(mapper, boundsInPixelsForRightMonitor, 100) };
4748
}
4849

49-
Stream<CoordinateSystemMapper> provideCoordinateSystemMappers() {
50-
return Stream.of(new MultiZoomCoordinateSystemMapper(null, () -> monitors),
51-
new SingleZoomCoordinateSystemMapper(null));
50+
private Stream<CoordinateSystemMapper> provideCoordinateSystemMappers() {
51+
return Stream.of(getMultiZoomCoordinateSystemMapper(), getSingleZoomCoordinateSystemMapper());
52+
}
53+
54+
private MultiZoomCoordinateSystemMapper getMultiZoomCoordinateSystemMapper() {
55+
return new MultiZoomCoordinateSystemMapper(null, () -> monitors);
56+
}
57+
58+
private SingleZoomCoordinateSystemMapper getSingleZoomCoordinateSystemMapper() {
59+
return new SingleZoomCoordinateSystemMapper(null);
5260
}
5361

5462
@ParameterizedTest
@@ -60,16 +68,27 @@ void translatePointInNoMonitorBackAndForthShouldBeTheSame(CoordinateSystemMapper
6068
assertEquals(pt, mapper.translateFromDisplayCoordinates(px, monitors[0].getZoom()));
6169
}
6270

63-
@ParameterizedTest
64-
@MethodSource("provideCoordinateSystemMappers")
65-
@Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper")
66-
void translatePointInGapBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) {
71+
@Test
72+
void translatePointInGapBackAndForthInSingleZoomShouldBeTheSame() {
73+
SingleZoomCoordinateSystemMapper mapper = getSingleZoomCoordinateSystemMapper();
6774
setupMonitors(mapper);
6875
Point pt = new Point(1900, 400);
6976
Point px = mapper.translateToDisplayCoordinates(pt, monitors[0].getZoom());
7077
assertEquals(pt, mapper.translateFromDisplayCoordinates(px, monitors[0].getZoom()));
7178
}
7279

80+
@Test
81+
void translatePointInGapBackAndForthInMultiZoomShouldEndInsideTheSameMonitor() {
82+
MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper();
83+
setupMonitors(mapper);
84+
Point pt = new Point(1900, 400);
85+
Point px = mapper.translateToDisplayCoordinates(pt, monitors[0].getZoom());
86+
Point translatedPt = mapper.translateFromDisplayCoordinates(px, monitors[0].getZoom());
87+
Point translatedPx = mapper.translateToDisplayCoordinates(translatedPt, monitors[0].getZoom());
88+
assertEquals(translatedPt, translatedPx);
89+
assertEquals(translatedPx, px);
90+
}
91+
7392
@ParameterizedTest
7493
@MethodSource("provideCoordinateSystemMappers")
7594
void translateRectangleInNoMonitorBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) {
@@ -79,22 +98,46 @@ void translateRectangleInNoMonitorBackAndForthShouldBeTheSame(CoordinateSystemMa
7998
assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()));
8099
}
81100

82-
@ParameterizedTest
83-
@MethodSource("provideCoordinateSystemMappers")
84-
@Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper")
85-
void translateRectangleInGapBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) {
101+
@Test
102+
void translateRectangleInGapBackAndForthInSingleZoomShouldBeTheSame() {
103+
SingleZoomCoordinateSystemMapper mapper = getSingleZoomCoordinateSystemMapper();
86104
setupMonitors(mapper);
87105
Rectangle rectInPts = new Rectangle(1800, 400, 100, 100);
88106
Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom());
89107
assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()));
90108
}
91109

92-
@ParameterizedTest
93-
@MethodSource("provideCoordinateSystemMappers")
94-
@Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper")
95-
void translateRectangleInGapPartiallyInRightBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) {
110+
@Test
111+
void translateRectangleInGapBackAndForthInMultiZoomShouldBeInMonitorBounds() {
112+
MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper();
113+
setupMonitors(mapper);
114+
Rectangle rectInPts = new Rectangle(1800, 400, 100, 100);
115+
Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom());
116+
Rectangle rectInPtsTranslated = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom());
117+
boolean isInsideMonitor = false;
118+
for (Monitor monitor : monitors) {
119+
if (monitor.getClientArea().intersects(rectInPtsTranslated)) {
120+
isInsideMonitor = true;
121+
break;
122+
}
123+
}
124+
assertTrue(isInsideMonitor, "The translated rectangle in points is inside the monitor bounds in points");
125+
}
126+
127+
@Test
128+
void translateRectangleInGapPartiallyInRightBackAndForthInSingleZoomShouldBeTheSame() {
129+
SingleZoomCoordinateSystemMapper mapper = getSingleZoomCoordinateSystemMapper();
130+
setupMonitors(mapper);
131+
Rectangle rectInPts = new Rectangle(1950, 400, 150, 100);
132+
Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom());
133+
assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()));
134+
}
135+
136+
@Test
137+
void translateRectangleInGapPartiallyInRightBackAndForthInMultiZoomShouldBeInside() {
138+
MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper();
96139
setupMonitors(mapper);
97-
Rectangle rectInPts = new Rectangle(1950, 400, 100, 100);
140+
Rectangle rectInPts = new MonitorAwareRectangle(1950, 400, 150, 100, monitors[1]);
98141
Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom());
99142
assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()));
100143
}
@@ -108,19 +151,30 @@ void translateRectangleInGapPartiallyInLeftBackAndForthShouldBeTheSame(Coordinat
108151
assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()));
109152
}
110153

111-
@ParameterizedTest
112-
@MethodSource("provideCoordinateSystemMappers")
113-
void translateRectangleInPointsInBothMonitorsPartiallyBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) {
154+
@Test
155+
void translateRectangleInPointsInBothMonitorsPartiallyBackAndForthInSingleZoomShouldBeTheSame() {
156+
SingleZoomCoordinateSystemMapper mapper = getSingleZoomCoordinateSystemMapper();
114157
setupMonitors(mapper);
115158
Rectangle rectInPts = new Rectangle(950, 400, 1500, 100);
116159
Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom());
117160
assertEquals(rectInPts, mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom()));
118161
}
119162

120163
@Test
121-
@Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper")
164+
void translateRectangleInPointsInBothMonitorsPartiallyBackAndForthInMultiZoomShouldNotEndUpInGap() {
165+
MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper();
166+
setupMonitors(mapper);
167+
Rectangle rectInPts = new Rectangle(950, 400, 1500, 100);
168+
Rectangle rectInPxs = mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom());
169+
Rectangle rectInPtsTranslated = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom());
170+
Rectangle rectInPxsTranslated = mapper.translateToDisplayCoordinates(rectInPtsTranslated,
171+
monitors[0].getZoom());
172+
assertEquals(rectInPxs, rectInPxsTranslated);
173+
}
174+
175+
@Test
122176
void moveRectangleInPixelsInRightMonitorsPartiallyBackAndForthShouldBeTheSame() {
123-
CoordinateSystemMapper mapper = provideCoordinateSystemMappers().findFirst().get();
177+
MultiZoomCoordinateSystemMapper mapper = getMultiZoomCoordinateSystemMapper();
124178
setupMonitors(mapper);
125179
Rectangle rectInPxs = new Rectangle(1990, -10, 2000, 2000);
126180
Rectangle expectedSmallRectInPxs = new Rectangle(0, 0, 0, monitors[0].getZoom());
@@ -140,10 +194,9 @@ void moveRectangleInPixelsInRightMonitorsPartiallyBackAndForthShouldBeTheSame()
140194

141195
@ParameterizedTest
142196
@MethodSource("provideCoordinateSystemMappers")
143-
@Disabled("Disabled due to current limitations of MultiZoomCoordinateSystemMapper")
144197
void translateRectangleInPixelsOutisdeMonitorsBackAndForthShouldBeTheSame(CoordinateSystemMapper mapper) {
145198
setupMonitors(mapper);
146-
Rectangle rectInPxs = new Rectangle(4400, 400, 1000, 1000);
199+
Rectangle rectInPxs = new Rectangle(400, 2400, 1000, 1000);
147200
Rectangle rectInPts = mapper.translateFromDisplayCoordinates(rectInPxs, monitors[0].getZoom());
148201
assertEquals(rectInPxs, mapper.translateToDisplayCoordinates(rectInPts, monitors[0].getZoom()));
149202
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Yatta Solutions and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Yatta Solutions - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.swt.graphics;
15+
16+
import org.eclipse.swt.widgets.*;
17+
18+
/**
19+
* Instances of this class represent {@link org.eclipse.swt.graphics.Point}
20+
* objects along with the context of the monitor in relation to which they are
21+
* placed on the display. The monitor awareness makes it easy to scale and
22+
* translate the points between pixels and points.
23+
*
24+
* @since 3.129
25+
* @noreference This class is not intended to be referenced by clients
26+
*/
27+
public final class MonitorAwarePoint extends Point {
28+
29+
private static final long serialVersionUID = 6077427420686999194L;
30+
31+
private final Monitor monitor;
32+
33+
/**
34+
* Constructs a new MonitorAwarePoint
35+
*
36+
* @param x the x coordinate of the point
37+
* @param y the y coordinate of the point
38+
* @param monitor the monitor with whose context the point is created
39+
*/
40+
public MonitorAwarePoint(int x, int y, Monitor monitor) {
41+
super(x, y);
42+
this.monitor = monitor;
43+
}
44+
45+
/**
46+
* {@return the monitor with whose context the instance is created}
47+
*/
48+
public Monitor getMonitor() {
49+
return monitor;
50+
}
51+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Yatta Solutions and others.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*
11+
* Contributors:
12+
* Yatta Solutions - initial API and implementation
13+
*******************************************************************************/
14+
package org.eclipse.swt.graphics;
15+
16+
import org.eclipse.swt.widgets.*;
17+
18+
/**
19+
* Instances of this class represent {@link org.eclipse.swt.graphics.Rectangle}
20+
* objects along with the context of the monitor in relation to which they are
21+
* placed on the display. The monitor awareness makes it easy to scale and
22+
* translate the rectangles between pixels and points.
23+
*
24+
* @since 3.129
25+
* @noreference This class is not intended to be referenced by clients
26+
*/
27+
public final class MonitorAwareRectangle extends Rectangle {
28+
29+
private static final long serialVersionUID = 5041911840525116925L;
30+
31+
private final Monitor monitor;
32+
33+
/**
34+
* Constructs a new MonitorAwareRectangle
35+
*
36+
* @param x the x coordinate of the top left corner of the rectangle
37+
* @param y the y coordinate of the top left corner of the rectangle
38+
* @param width the width of the rectangle
39+
* @param height the height of the rectangle
40+
* @param monitor the monitor with whose context the rectangle is created
41+
*/
42+
public MonitorAwareRectangle(int x, int y, int width, int height, Monitor monitor) {
43+
super(x, y, width, height);
44+
this.monitor = monitor;
45+
}
46+
47+
/**
48+
* {@return the monitor with whose context the instance is created}
49+
*/
50+
public Monitor getMonitor() {
51+
return monitor;
52+
}
53+
}

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Point.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
4242
*/
4343

44-
public final class Point implements Serializable {
44+
public sealed class Point implements Serializable permits MonitorAwarePoint {
4545

4646
/**
4747
* the x coordinate of the point

bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/graphics/Rectangle.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
* @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
4646
*/
4747

48-
public final class Rectangle implements Serializable {
48+
public sealed class Rectangle implements Serializable permits MonitorAwareRectangle {
4949

5050
/**
5151
* the x coordinate of the rectangle

0 commit comments

Comments
 (0)