X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.utils.ui%2Fsrc%2Forg%2Fsimantics%2Futils%2Fui%2FSWTDPIUtil.java;fp=bundles%2Forg.simantics.utils.ui%2Fsrc%2Forg%2Fsimantics%2Futils%2Fui%2FSWTDPIUtil.java;h=962276432b223fa1138ef3f2a9f6628f02b6ecad;hb=df4c45d1132f66008d2889738048363e79f94ebe;hp=0000000000000000000000000000000000000000;hpb=74083d12acc3169cbeb36f39b3f4837ffdc34233;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTDPIUtil.java b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTDPIUtil.java new file mode 100644 index 000000000..962276432 --- /dev/null +++ b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTDPIUtil.java @@ -0,0 +1,232 @@ +package org.simantics.utils.ui; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.internal.DPIUtil; + +/** + * This class is needed to support {@link SWTAWTComponent} and HiDPI screens + * with different display zoom settings. + * + *

+ * See {@link DPIUtil} for explanations on what downscaling and upscaling are in + * this context. If user has zoom > 100% in use in the system display settings, + * SWT's API coordinates will be "downscaled" from actual internal HiDPI + * coordinates (pixels). + * + *

+ * This class contains methods to work around problems with e.g. opening context + * menu's in the correct location when using {@link SWTAWTComponent}. AWT always + * returns HiDPI pixel coordinates which need to be converted to SWT API + * coordinates before giving them to any SWT APIs. + * + * @author Tuukka Lehtonen + * @since 1.36.0 + */ +@SuppressWarnings("restriction") +public class SWTDPIUtil { + + private static boolean initialized = false; + private static int swtZoom; + private static boolean hasSwtScale; + + private static float fromSwtInternalScalingFactorF; + private static double fromSwtInternalScalingFactorD; + private static float toSwtInternalScalingFactorF; + private static double toSwtInternalScalingFactorD; + + private static void initialize() { + if (initialized) + return; + + swtZoom = DPIUtil.autoScaleUp(100); + hasSwtScale = swtZoom != 100; + + fromSwtInternalScalingFactorD = 100.0 / (double) swtZoom; + toSwtInternalScalingFactorD = (double) swtZoom / 100.0; + fromSwtInternalScalingFactorF = (float) fromSwtInternalScalingFactorD; + toSwtInternalScalingFactorF = (float) toSwtInternalScalingFactorD; + +// System.out.format("SWTDPIUtil:%n\tswt zoom = %d%n\tfrom swt internal scaling factor = %f%n\tto swt internal scaling factor = %f%n", +// swtZoom, +// fromSwtInternalScalingFactorD, +// toSwtInternalScalingFactorD, +// ); + + initialized = true; + } + + // Internals + + private static Rectangle scale(float s, Rectangle r, Rectangle target) { + if (s == 1.0f) { + if (r == target) + return r; + if (target == null) { + return new Rectangle(r.x, r.y, r.width, r.height); + } else { + target.x = r.x; + target.y = r.y; + target.width = r.width; + target.height = r.height; + return target; + } + } + if (target == null) { + return new Rectangle( + Math.round(r.x*s), + Math.round(r.y*s), + Math.round(r.width*s), + Math.round(r.height*s)); + } else { + target.x = Math.round(r.x*s); + target.y = Math.round(r.y*s); + target.width = Math.round(r.width*s); + target.height = Math.round(r.height*s); + return target; + } + } + + private static Rectangle2D scale(double s, Rectangle2D r, Rectangle2D target) { + if (s == 1.0) { + if (r == target) + return r; + if (target == null) + return (Rectangle2D) r.clone(); + target.setFrame(r); + return target; + } + if (target == null) + target = (Rectangle2D) r.clone(); + target.setFrame(r.getX()*s, r.getY()*s, r.getWidth()*s, r.getHeight()*s); + return target; + } + + // SWT API Coordinates <-> pixels + + public static double downscaleSwt(double x) { + initialize(); + return hasSwtScale ? x * fromSwtInternalScalingFactorD : x; + } + + public static int downscaleSwt(int x) { + if (!hasSwtScale) + return x; + return (int) Math.round(downscaleSwt((double) x)); + } + + public static Point2D downscaleSwt(double x, double y) { + initialize(); + if (!hasSwtScale) + return new Point2D.Double(x, y); + double s = fromSwtInternalScalingFactorD; + return new Point2D.Double(x * s, y * s); + } + + public static Point downscaleSwt(int x, int y) { + return new Point(downscaleSwt(x), downscaleSwt(y)); + } + + public static Point2D downscaleSwt(Point2D p) { + return downscaleSwt(p.getX(), p.getY()); + } + + public static Point downscaleSwtToInteger(Point2D p) { + return new Point( + (int) Math.round(downscaleSwt(p.getX())), + (int) Math.round(downscaleSwt(p.getY()))); + } + + public static Rectangle2D downscaleSwt(Rectangle2D r, Rectangle2D target) { + initialize(); + return scale(fromSwtInternalScalingFactorD, r, target); + } + + public static Rectangle2D downscaleSwt(Rectangle2D r) { + return downscaleSwt(r, null); + } + + public static Rectangle downscaleSwt(Rectangle r, Rectangle target) { + initialize(); + return scale(fromSwtInternalScalingFactorF, r, target); + } + + public static Rectangle downscaleSwt(Rectangle r) { + return downscaleSwt(r, null); + } + + public static Rectangle downscaleSwtToInteger(Rectangle2D r) { + return new Rectangle( + (int) Math.round(downscaleSwt(r.getMinX())), + (int) Math.round(downscaleSwt(r.getMinY())), + (int) Math.round(downscaleSwt(r.getWidth())), + (int) Math.round(downscaleSwt(r.getHeight()))); + } + + public static double upscaleSwt(double x) { + initialize(); + return hasSwtScale ? x * toSwtInternalScalingFactorD : x; + } + + public static int upscaleSwt(int x) { + initialize(); + if (!hasSwtScale) + return x; + return (int) Math.round((double) x * toSwtInternalScalingFactorD); + } + + public static Point2D upscaleSwt(double x, double y) { + if (!hasSwtScale) + return new Point2D.Double(x, y); + double s = toSwtInternalScalingFactorD; + return new Point2D.Double(x * s, y * s); + } + + public static Point upscaleSwt(int x, int y) { + return new Point(upscaleSwt(x), upscaleSwt(y)); + } + + public static Point2D upscaleSwt(Point2D p) { + return upscaleSwt(p.getX(), p.getY()); + } + + public static Point upscaleSwtToInteger(Point2D p) { + return new Point( + (int) Math.round(upscaleSwt(p.getX())), + (int) Math.round(upscaleSwt(p.getY()))); + } + + public static Point upscaleSwt(Point p) { + return upscaleSwt(p.x, p.y); + } + + public static Rectangle2D upscaleSwt(Rectangle2D r, Rectangle2D target) { + initialize(); + return scale(toSwtInternalScalingFactorD, r, target); + } + + public static Rectangle upscaleSwt(Rectangle r, Rectangle target) { + initialize(); + return scale(toSwtInternalScalingFactorF, r, target); + } + + public static Rectangle2D upscaleSwt(Rectangle2D r) { + return upscaleSwt(r, null); + } + + public static Rectangle upscaleSwt(Rectangle r) { + return upscaleSwt(r, null); + } + + public static Rectangle upscaleSwtToInteger(Rectangle2D r) { + return new Rectangle( + (int) Math.round(upscaleSwt(r.getMinX())), + (int) Math.round(upscaleSwt(r.getMinY())), + (int) Math.round(upscaleSwt(r.getWidth())), + (int) Math.round(upscaleSwt(r.getHeight()))); + } + +}