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 private static double downscaleSwt0(double x) {
109 return hasSwtScale ? x * fromSwtInternalScalingFactorD : x;
112 private static int downscaleToIntegerSwt0(double x) {
113 return (int)(hasSwtScale ? Math.round((double) x * fromSwtInternalScalingFactorD) : x);
116 private static int downscaleSwt0(int x) {
117 return hasSwtScale ? (int) Math.round((double) x * fromSwtInternalScalingFactorD) : x;
120 private static double upscaleSwt0(double x) {
121 return hasSwtScale ? x * toSwtInternalScalingFactorD : x;
124 private static int upscaleToIntegerSwt0(double x) {
125 return (int)(hasSwtScale ? Math.round((double) x * toSwtInternalScalingFactorD) : x);
128 private static int upscaleSwt0(int x) {
129 return hasSwtScale ? (int) Math.round((double) x * toSwtInternalScalingFactorD) : x;
132 // SWT API Coordinates <-> pixels
136 public static double downscaleSwt(double x) {
138 return downscaleSwt0(x);
141 public static int downscaleSwt(int x) {
143 return downscaleSwt0(x);
146 public static Point2D downscaleSwt(double x, double y) {
149 return new Point2D.Double(x, y);
150 double s = fromSwtInternalScalingFactorD;
151 return new Point2D.Double(x * s, y * s);
154 public static Point downscaleSwt(int x, int y) {
156 return new Point(downscaleSwt0(x), downscaleSwt0(y));
159 public static Point2D downscaleSwt(Point2D p) {
160 return downscaleSwt(p.getX(), p.getY());
163 public static Point downscaleSwtToInteger(Point2D p) {
165 return new Point(downscaleToIntegerSwt0(p.getX()), downscaleToIntegerSwt0(p.getY()));
168 public static Rectangle2D downscaleSwt(Rectangle2D r, Rectangle2D target) {
170 return scale(fromSwtInternalScalingFactorD, r, target);
173 public static Rectangle2D downscaleSwt(Rectangle2D r) {
174 return downscaleSwt(r, null);
177 public static Rectangle downscaleSwt(Rectangle r, Rectangle target) {
179 return scale(fromSwtInternalScalingFactorF, r, target);
182 public static Rectangle downscaleSwt(Rectangle r) {
183 return downscaleSwt(r, null);
186 public static Rectangle downscaleSwtToInteger(Rectangle2D r) {
188 return new Rectangle(
189 downscaleToIntegerSwt0(r.getMinX()),
190 downscaleToIntegerSwt0(r.getMinY()),
191 downscaleToIntegerSwt0(r.getWidth()),
192 downscaleToIntegerSwt0(r.getHeight()));
197 public static double upscaleSwt(double x) {
199 return upscaleSwt0(x);
202 public static int upscaleSwt(int x) {
204 return upscaleSwt0(x);
207 public static Point2D upscaleSwt(double x, double y) {
210 return new Point2D.Double(x, y);
211 double s = toSwtInternalScalingFactorD;
212 return new Point2D.Double(x * s, y * s);
215 public static Point upscaleSwt(int x, int y) {
217 return new Point(upscaleSwt0(x), upscaleSwt0(y));
220 public static Point2D upscaleSwt(Point2D p) {
221 return upscaleSwt(p.getX(), p.getY());
224 public static Point upscaleSwtToInteger(Point2D p) {
226 return new Point(upscaleToIntegerSwt0(p.getX()), upscaleToIntegerSwt0(p.getY()));
229 public static Point upscaleSwt(Point p) {
230 return upscaleSwt(p.x, p.y);
233 public static Rectangle2D upscaleSwt(Rectangle2D r, Rectangle2D target) {
235 return scale(toSwtInternalScalingFactorD, r, target);
238 public static Rectangle upscaleSwt(Rectangle r, Rectangle target) {
240 return scale(toSwtInternalScalingFactorF, r, target);
243 public static Rectangle2D upscaleSwt(Rectangle2D r) {
244 return upscaleSwt(r, null);
247 public static Rectangle upscaleSwt(Rectangle r) {
248 return upscaleSwt(r, null);
251 public static Rectangle upscaleSwtToInteger(Rectangle2D r) {
252 return new Rectangle(
253 upscaleToIntegerSwt0(r.getMinX()),
254 upscaleToIntegerSwt0(r.getMinY()),
255 upscaleToIntegerSwt0(r.getWidth()),
256 upscaleToIntegerSwt0(r.getHeight()));