]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTDPIUtil.java
Small but effective HiDPI fixes for platform G2D
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / SWTDPIUtil.java
1 package org.simantics.utils.ui;
2
3 import java.awt.geom.Point2D;
4 import java.awt.geom.Rectangle2D;
5
6 import org.eclipse.swt.graphics.Point;
7 import org.eclipse.swt.graphics.Rectangle;
8 import org.eclipse.swt.internal.DPIUtil;
9
10 /**
11  * This class is needed to support {@link SWTAWTComponent} and HiDPI screens
12  * with different display zoom settings.
13  * 
14  * <p>
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).
19  * 
20  * <p>
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.
25  *
26  * @author Tuukka Lehtonen
27  * @since 1.36.0
28  */
29 @SuppressWarnings("restriction")
30 public class SWTDPIUtil {
31
32         private static boolean initialized = false;
33         private static int swtZoom;
34         private static boolean hasSwtScale;
35
36         private static float fromSwtInternalScalingFactorF;
37         private static double fromSwtInternalScalingFactorD;
38         private static float toSwtInternalScalingFactorF;
39         private static double toSwtInternalScalingFactorD;
40
41         private static void initialize() {
42                 if (initialized)
43                         return;
44
45                 swtZoom = DPIUtil.autoScaleUp(100);
46                 hasSwtScale = swtZoom != 100;
47
48                 fromSwtInternalScalingFactorD         = 100.0 / (double) swtZoom;
49                 toSwtInternalScalingFactorD           = (double) swtZoom / 100.0;
50                 fromSwtInternalScalingFactorF         = (float) fromSwtInternalScalingFactorD;
51                 toSwtInternalScalingFactorF           = (float) toSwtInternalScalingFactorD;
52
53 //              System.out.format("SWTDPIUtil:%n\tswt zoom = %d%n\tfrom swt internal scaling factor = %f%n\tto swt internal scaling factor = %f%n",
54 //                              swtZoom,
55 //                              fromSwtInternalScalingFactorD,
56 //                              toSwtInternalScalingFactorD,
57 //                              );
58
59                 initialized = true;
60         }
61
62         // Internals
63
64         private static Rectangle scale(float s, Rectangle r, Rectangle target) {
65                 if (s == 1.0f) {
66                         if (r == target)
67                                 return r;
68                         if (target == null) {
69                                 return new Rectangle(r.x, r.y, r.width, r.height);
70                         } else {
71                                 target.x = r.x;
72                                 target.y = r.y;
73                                 target.width = r.width;
74                                 target.height = r.height;
75                                 return target;
76                         }
77                 }
78                 if (target == null) {
79                         return new Rectangle(
80                                         Math.round(r.x*s),
81                                         Math.round(r.y*s),
82                                         Math.round(r.width*s),
83                                         Math.round(r.height*s));
84                 } else {
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);
89                         return target;
90                 }
91         }
92
93         private static Rectangle2D scale(double s, Rectangle2D r, Rectangle2D target) {
94                 if (s == 1.0) {
95                         if (r == target)
96                                 return r;
97                         if (target == null)
98                                 return (Rectangle2D) r.clone();
99                         target.setFrame(r);
100                         return target;
101                 }
102                 if (target == null)
103                         target = (Rectangle2D) r.clone();
104                 target.setFrame(r.getX()*s, r.getY()*s, r.getWidth()*s, r.getHeight()*s);
105                 return target;
106         }
107
108         // SWT API Coordinates <-> pixels
109
110         public static double downscaleSwt(double x) {
111                 initialize();
112                 return hasSwtScale ? x * fromSwtInternalScalingFactorD : x;
113         }
114
115         public static int downscaleSwt(int x) {
116                 if (!hasSwtScale)
117                         return x;
118                 return (int) Math.round(downscaleSwt((double) x));
119         }
120
121         public static Point2D downscaleSwt(double x, double y) {
122                 initialize();
123                 if (!hasSwtScale)
124                         return new Point2D.Double(x, y);
125                 double s = fromSwtInternalScalingFactorD;
126                 return new Point2D.Double(x * s, y * s);
127         }
128
129         public static Point downscaleSwt(int x, int y) {
130                 return new Point(downscaleSwt(x), downscaleSwt(y));
131         }
132
133         public static Point2D downscaleSwt(Point2D p) {
134                 return downscaleSwt(p.getX(), p.getY());
135         }
136
137         public static Point downscaleSwtToInteger(Point2D p) {
138                 return new Point(
139                                 (int) Math.round(downscaleSwt(p.getX())),
140                                 (int) Math.round(downscaleSwt(p.getY())));
141         }
142
143         public static Rectangle2D downscaleSwt(Rectangle2D r, Rectangle2D target) {
144                 initialize();
145                 return scale(fromSwtInternalScalingFactorD, r, target);
146         }
147
148         public static Rectangle2D downscaleSwt(Rectangle2D r) {
149                 return downscaleSwt(r, null);
150         }
151
152         public static Rectangle downscaleSwt(Rectangle r, Rectangle target) {
153                 initialize();
154                 return scale(fromSwtInternalScalingFactorF, r, target);
155         }
156
157         public static Rectangle downscaleSwt(Rectangle r) {
158                 return downscaleSwt(r, null);
159         }
160
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())));
167         }
168
169         public static double upscaleSwt(double x) {
170                 initialize();
171                 return hasSwtScale ? x * toSwtInternalScalingFactorD : x;
172         }
173
174         public static int upscaleSwt(int x) {
175                 initialize();
176                 if (!hasSwtScale)
177                         return x;
178                 return (int) Math.round((double) x * toSwtInternalScalingFactorD);
179         }
180
181         public static Point2D upscaleSwt(double x, double y) {
182                 if (!hasSwtScale)
183                         return new Point2D.Double(x, y);
184                 double s = toSwtInternalScalingFactorD;
185                 return new Point2D.Double(x * s, y * s);
186         }
187
188         public static Point upscaleSwt(int x, int y) {
189                 return new Point(upscaleSwt(x), upscaleSwt(y));
190         }
191
192         public static Point2D upscaleSwt(Point2D p) {
193                 return upscaleSwt(p.getX(), p.getY());
194         }
195
196         public static Point upscaleSwtToInteger(Point2D p) {
197                 return new Point(
198                                 (int) Math.round(upscaleSwt(p.getX())),
199                                 (int) Math.round(upscaleSwt(p.getY())));
200         }
201
202         public static Point upscaleSwt(Point p) {
203                 return upscaleSwt(p.x, p.y);
204         }
205
206         public static Rectangle2D upscaleSwt(Rectangle2D r, Rectangle2D target) {
207                 initialize();
208                 return scale(toSwtInternalScalingFactorD, r, target);
209         }
210
211         public static Rectangle upscaleSwt(Rectangle r, Rectangle target) {
212                 initialize();
213                 return scale(toSwtInternalScalingFactorF, r, target);
214         }
215
216         public static Rectangle2D upscaleSwt(Rectangle2D r) {
217                 return upscaleSwt(r, null);
218         }
219
220         public static Rectangle upscaleSwt(Rectangle r) {
221                 return upscaleSwt(r, null);
222         }
223
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())));
230         }
231
232 }