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