001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.tools;
003
004import java.awt.Dimension;
005import java.awt.GraphicsEnvironment;
006import java.awt.Toolkit;
007
008import org.openstreetmap.josm.spi.preferences.Config;
009
010/**
011 * Support class to handle size information of Gui elements
012 * This is needed, because display resolution may vary a lot and a common set
013 * of sizes wont work for all users alike.
014 * @since 12682 (moved from {@code gui.util} package)
015 * @since 10358
016 */
017public final class GuiSizesHelper {
018
019    private GuiSizesHelper() {
020        // Hide default constructor for utils classes
021    }
022
023    /** cache value for screen resolution */
024    private static float screenDPI = -1;
025
026    /**
027     * Request the screen resolution (cached)
028     * @return screen resolution in DPI
029     */
030    private static float getScreenDPI() {
031        if (screenDPI == -1) {
032            synchronized (GuiSizesHelper.class) {
033                if (screenDPI == -1) {
034                    float scalePref = (float) Config.getPref().getDouble("gui.scale", 1.0);
035                    if (scalePref != 0) {
036                        screenDPI = 96f * scalePref;
037                    } else {
038                        if (!GraphicsEnvironment.isHeadless()) {
039                            screenDPI = Toolkit.getDefaultToolkit().getScreenResolution();
040                        } else {
041                            screenDPI = 96;
042                        }
043                    }
044                }
045            }
046        }
047        return screenDPI;
048    }
049
050    /**
051     * Returns coefficient of monitor pixel density. All hardcoded sizes must be multiplied by this value.
052     *
053     * @return float value. 1 - means standard monitor, 2 and high - "retina" display.
054     */
055    public static float getPixelDensity() {
056        return getScreenDPI() / 96f;
057    }
058
059    /**
060     * Sets coefficient of monitor pixel density.
061     * @param pixelDensity coefficient of monitor pixel density to be set.
062     */
063    public static void setPixelDensity(float pixelDensity) {
064        screenDPI = pixelDensity * 96f;
065    }
066
067    /**
068     * Check if a high DPI resolution is used
069     * @return <code>true</code> for HIDPI screens
070     */
071    public static boolean isHiDPI() {
072        return getPixelDensity() >= 2f;
073    }
074
075    /**
076     * Returns a resolution adapted size
077     * @param size Size value to adapt (base size is a low DPI screen)
078     * @return adapted size (may be unmodified)
079     */
080    public static int getSizeDpiAdjusted(int size) {
081        if (size <= 0) return size;
082        return Math.round(size * getScreenDPI() / 96);
083    }
084
085    /**
086     * Returns a resolution adapted size
087     * @param size Size value to adapt (base size is a low DPI screen)
088     * @return adapted size (may be unmodified)
089     */
090    public static float getSizeDpiAdjusted(float size) {
091        if (size <= 0f) return size;
092        return size * getScreenDPI() / 96;
093    }
094
095    /**
096     * Returns a resolution adapted size
097     * @param size Size value to adapt (base size is a low DPI screen)
098     * @return adapted size (may be unmodified)
099     */
100    public static double getSizeDpiAdjusted(double size) {
101        if (size <= 0d) return size;
102        return size * getScreenDPI() / 96;
103    }
104
105    /**
106     * Returns a resolution adapted Dimension
107     * @param dim Dimension value to adapt (base size is a low DPI screen)
108     * @return adapted dimension (may be unmodified)
109     */
110    public static Dimension getDimensionDpiAdjusted(Dimension dim) {
111        float pixelPerInch = getScreenDPI();
112        int width = dim.width;
113        int height = dim.height;
114        if (dim.width > 0) {
115            width = Math.round(dim.width * pixelPerInch / 96);
116        }
117
118        if (dim.height > 0) {
119            height = Math.round(dim.height * pixelPerInch / 96);
120        }
121
122        return new Dimension(width, height);
123    }
124}