com.actelion.research.gui.hidpi.HiDPIHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
package com.actelion.research.gui.hidpi;
import com.actelion.research.gui.LookAndFeelHelper;
import com.actelion.research.gui.generic.GenericImage;
import com.actelion.research.util.ColorHelper;
import com.actelion.research.util.Platform;
import javax.swing.*;
import java.awt.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
public class HiDPIHelper {
// This is an Apple only solution and needs to be adapted to support high-res displays of other vendors
private static float sRetinaFactor = -1f;
private static float sUIScaleFactor = -1f;
private static float sIconScaleFactor = -1f;
private static float sPixelPerComponentSizeFactor = -1f;
/**
* Macintosh retina display support for Java 7 and newer.
*
* @return 1.0 on standard resolution devices and 2.0 for retina screens
*/
public static float getRetinaScaleFactor() {
if (!Platform.isMacintosh())
return 1f;
if (sRetinaFactor != -1f)
return sRetinaFactor;
sRetinaFactor = 1f;
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice device = env.getDefaultScreenDevice();
if (System.getProperty("java.version").startsWith("1.")) { // for JRE8 and earlier
try {
Field field = device.getClass().getDeclaredField("scale");
field.setAccessible(true);
Object scale = field.get(device);
if (scale instanceof Integer)
sRetinaFactor = (Integer) scale;
else
System.out.println("Unexpected content scale (not 1 nor 2): " + scale.toString());
}
catch (Throwable e) {}
}
else {
GraphicsDevice sd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
sRetinaFactor = (float) sd.getDefaultConfiguration().getDefaultTransform().getScaleX();
}
return sRetinaFactor;
}
/**
* For Windows and Linux this method returns a (hopefully) reasonable UI scaling factor.
* If DataWarrior was launched with a user supplied system property 'dpifactor', then we use
* this value. Otherwise, we take the screen resolution devided by 96, which finally results
* in a scaling factor of 1.0 at 96 dpi monitor resolution. If we use factor*12 point system
* fonts, then these are about 3 mm high on monitors independent of their resolution.
* On the Macintosh this factor is 1.0, because HiDPI device support uses
* a different mechanism on OSX (see getRetinaScaleFactor()).
* @return typically 1.0 or 1.25, 1.5, ...
*/
public static float getUIScaleFactor() {
if (sUIScaleFactor == -1) {
float f = 0;
String dpiFactor = System.getProperty("dpifactor");
if (dpiFactor != null)
try { f = Float.parseFloat(dpiFactor); } catch (NumberFormatException nfe) {}
if (f != 0)
sUIScaleFactor = f;
else if (Platform.isMacintosh()) {
sUIScaleFactor = 1.0f;
}
else if (Platform.isWindows()) {
// only do scaling if jre <= 1.8
if (System.getProperty("java.version").startsWith("1.")) {
try {
// with JRE8 we used (float)UIManager.getFont("Label.font").getSize() / 12f
sUIScaleFactor = Toolkit.getDefaultToolkit().getScreenResolution() / 96f;
} catch (HeadlessException hle) {
sUIScaleFactor = 1.0f;
}
} else {
sUIScaleFactor = 1.0f;
}
}
else { // Linux; Toolkit.getDefaultToolkit().getScreenResolution() always returns 1.0
try {
sUIScaleFactor = 1.0f; // default in case of error
Process process = Runtime.getRuntime().exec("xrdb -q");
process.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
String line;
while ((line = br.readLine()) != null) {
if (line.startsWith("Xft.dpi:")) {
int dpi = Integer.parseInt(line.substring(8).trim());
sUIScaleFactor = dpi / 96f;
break;
}
}
br.close();
}
catch (Exception ioe) {}
}
if (sUIScaleFactor < 1.1f)
sUIScaleFactor = 1.0f;
}
return sUIScaleFactor;
}
/**
* Depending on the operating system, reported sizes for Java components are often smaller
* than the real number of pixels if high resolution monitors are used.
* This method is supposed to report the factor needed between these.
* Note: For a multiscreen setup, ideally, this should be screen dependent.
* @return the (largest) image scaling factor of all connected screens
*/
public static float getPixelPerComponentSizeFactor() {
if (sPixelPerComponentSizeFactor == -1)
sPixelPerComponentSizeFactor = Platform.isWindows() ? getMaxDeviceUIScaling() : Platform.isMacintosh() ? getRetinaScaleFactor() : 1.0f;
return sPixelPerComponentSizeFactor;
}
/**
* Factor describing the screen resolution increase (of highest resolution device) in regard to 96-dpi
* @return
*/
public static float getIconScaleFactor() {
if (sIconScaleFactor == -1)
sIconScaleFactor = Platform.isWindows() ? getMaxDeviceUIScaling() : Platform.isMacintosh() ? getRetinaScaleFactor() : getUIScaleFactor();
return sIconScaleFactor;
}
public static void setUIScaleFactor(float factor) {
sUIScaleFactor = factor;
}
/**
* This is a convenience method that scales the passed int value with getUIScaleFactor()
* and returns the rounded result.
* @param value
* @return
*/
public static int scale(float value) {
return Math.round(getUIScaleFactor() * value);
}
/**
* This is a convenience method that scales the passed int value with getUIScaleFactor()
* and with getRetinaScaleFactor() and returns the rounded result.
* @param value
* @return
*/
public static int scaleRetinaAndUI(float value) {
return Math.round(getUIScaleFactor() * getRetinaScaleFactor() * value);
}
private static float getMaxDeviceUIScaling() {
double scaling = 1.0;
for (GraphicsDevice gd : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
double deviceScaling = gd.getDisplayMode().getWidth() / (double)gd.getDefaultConfiguration().getBounds().width;
scaling = Math.max(scaling, deviceScaling);
}
return (float)scaling;
}
/**
* If the current look&feel is dark, then colors are adapted for optimal contrast.
* @param image
* @return
*/
public static void disableImage(GenericImage image) {
Color gray = LookAndFeelHelper.isDarkLookAndFeel() ?
ColorHelper.brighter(UIManager.getColor("Panel.background"), 0.8f)
: ColorHelper.darker(UIManager.getColor("Panel.background"), 0.8f);
int grayRGB = 0x00FFFFFF & gray.getRGB();
for (int x=0; x