1 package org.simantics.utils.ui;
3 import java.awt.geom.Point2D;
4 import java.awt.geom.Rectangle2D;
6 import org.eclipse.swt.graphics.Point;
7 import org.eclipse.swt.graphics.Rectangle;
8 import org.eclipse.swt.internal.DPIUtil;
11 * This class is needed to support {@link SWTAWTComponent} and HiDPI screens
12 * with different display zoom settings.
15 * See {@link DPIUtil} for explanations on what downscaling and upscaling are in
16 * this context. If user has zoom > 100% in use in the system display settings,
17 * SWT's API coordinates will be "downscaled" from actual internal HiDPI
18 * coordinates (pixels).
21 * This class contains methods to work around problems with e.g. opening context
22 * menu's in the correct location when using {@link SWTAWTComponent}. AWT always
23 * returns HiDPI pixel coordinates which need to be converted to SWT API
24 * coordinates before giving them to any SWT APIs.
26 * @author Tuukka Lehtonen
29 @SuppressWarnings("restriction")
30 public class SWTDPIUtil {
32 private static boolean initialized = false;
33 private static int swtZoom;
34 private static boolean hasSwtScale;
36 private static float fromSwtInternalScalingFactorF;
37 private static double fromSwtInternalScalingFactorD;
38 private static float toSwtInternalScalingFactorF;
39 private static double toSwtInternalScalingFactorD;
41 private static void initialize() {
45 swtZoom = DPIUtil.autoScaleUp(100);
46 hasSwtScale = swtZoom != 100;
48 fromSwtInternalScalingFactorD = 100.0 / (double) swtZoom;
49 toSwtInternalScalingFactorD = (double) swtZoom / 100.0;
50 fromSwtInternalScalingFactorF = (float) fromSwtInternalScalingFactorD;
51 toSwtInternalScalingFactorF = (float) toSwtInternalScalingFactorD;
53 // System.out.format("SWTDPIUtil:%n\tswt zoom = %d%n\tfrom swt internal scaling factor = %f%n\tto swt internal scaling factor = %f%n",
55 // fromSwtInternalScalingFactorD,
56 // toSwtInternalScalingFactorD,
64 private static Rectangle scale(float s, Rectangle r, Rectangle target) {
69 return new Rectangle(r.x, r.y, r.width, r.height);
73 target.width = r.width;
74 target.height = r.height;
82 Math.round(r.width*s),
83 Math.round(r.height*s));
85 target.x = Math.round(r.x*s);
86 target.y = Math.round(r.y*s);
87 target.width = Math.round(r.width*s);
88 target.height = Math.round(r.height*s);
93 private static Rectangle2D scale(double s, Rectangle2D r, Rectangle2D target) {
98 return (Rectangle2D) r.clone();
103 target = (Rectangle2D) r.clone();
104 target.setFrame(r.getX()*s, r.getY()*s, r.getWidth()*s, r.getHeight()*s);
108 // SWT API Coordinates <-> pixels
110 public static double downscaleSwt(double x) {
112 return hasSwtScale ? x * fromSwtInternalScalingFactorD : x;
115 public static int downscaleSwt(int x) {
118 return (int) Math.round(downscaleSwt((double) x));
121 public static Point2D downscaleSwt(double x, double y) {
124 return new Point2D.Double(x, y);
125 double s = fromSwtInternalScalingFactorD;
126 return new Point2D.Double(x * s, y * s);
129 public static Point downscaleSwt(int x, int y) {
130 return new Point(downscaleSwt(x), downscaleSwt(y));
133 public static Point2D downscaleSwt(Point2D p) {
134 return downscaleSwt(p.getX(), p.getY());
137 public static Point downscaleSwtToInteger(Point2D p) {
139 (int) Math.round(downscaleSwt(p.getX())),
140 (int) Math.round(downscaleSwt(p.getY())));
143 public static Rectangle2D downscaleSwt(Rectangle2D r, Rectangle2D target) {
145 return scale(fromSwtInternalScalingFactorD, r, target);
148 public static Rectangle2D downscaleSwt(Rectangle2D r) {
149 return downscaleSwt(r, null);
152 public static Rectangle downscaleSwt(Rectangle r, Rectangle target) {
154 return scale(fromSwtInternalScalingFactorF, r, target);
157 public static Rectangle downscaleSwt(Rectangle r) {
158 return downscaleSwt(r, null);
161 public static Rectangle downscaleSwtToInteger(Rectangle2D r) {
162 return new Rectangle(
163 (int) Math.round(downscaleSwt(r.getMinX())),
164 (int) Math.round(downscaleSwt(r.getMinY())),
165 (int) Math.round(downscaleSwt(r.getWidth())),
166 (int) Math.round(downscaleSwt(r.getHeight())));
169 public static double upscaleSwt(double x) {
171 return hasSwtScale ? x * toSwtInternalScalingFactorD : x;
174 public static int upscaleSwt(int x) {
178 return (int) Math.round((double) x * toSwtInternalScalingFactorD);
181 public static Point2D upscaleSwt(double x, double y) {
183 return new Point2D.Double(x, y);
184 double s = toSwtInternalScalingFactorD;
185 return new Point2D.Double(x * s, y * s);
188 public static Point upscaleSwt(int x, int y) {
189 return new Point(upscaleSwt(x), upscaleSwt(y));
192 public static Point2D upscaleSwt(Point2D p) {
193 return upscaleSwt(p.getX(), p.getY());
196 public static Point upscaleSwtToInteger(Point2D p) {
198 (int) Math.round(upscaleSwt(p.getX())),
199 (int) Math.round(upscaleSwt(p.getY())));
202 public static Point upscaleSwt(Point p) {
203 return upscaleSwt(p.x, p.y);
206 public static Rectangle2D upscaleSwt(Rectangle2D r, Rectangle2D target) {
208 return scale(toSwtInternalScalingFactorD, r, target);
211 public static Rectangle upscaleSwt(Rectangle r, Rectangle target) {
213 return scale(toSwtInternalScalingFactorF, r, target);
216 public static Rectangle2D upscaleSwt(Rectangle2D r) {
217 return upscaleSwt(r, null);
220 public static Rectangle upscaleSwt(Rectangle r) {
221 return upscaleSwt(r, null);
224 public static Rectangle upscaleSwtToInteger(Rectangle2D r) {
225 return new Rectangle(
226 (int) Math.round(upscaleSwt(r.getMinX())),
227 (int) Math.round(upscaleSwt(r.getMinY())),
228 (int) Math.round(upscaleSwt(r.getWidth())),
229 (int) Math.round(upscaleSwt(r.getHeight())));