Support retina display

This forum is for discussion related to JIDE Icons.

Moderator: JIDE Support

Support retina display

Postby Radu » Wed Apr 01, 2015 5:50 am

Hi,

Jide comes with a couple of predefined icons.
For example for a Jide frame there are icons for toggle floating, toggle autohide and close.
There are two problems:

1) The predefined icons you have for toggle floating and close on Mac OSX "title_buttons.gif" are old style, they no longer reflect the flat layout Yosemite has + they are saved in a GIF which sometimes renders small artifacts around the borders when painted.
If you want we could give you the new set we have created to replace yours in our application.

2) When the JIDE library is used to display content on a high DPI monitor for Windows or on Retina display for Mac OSX the default icons start to look bad.
Ideally you would take into account the type of used display when painting your predefined icons.

For example on Mac OSX you can access the scaling factor used for display like:

Code: Select all
  /**
   * Gets the content scale factor for the retina display.
   *
   * @return The float representing the scaling factor. 1.0 means no scaling.
   */
  private static float getJava6ContentScaleFactor(){
    float scaleFactor = 1.0f;
    Object obj = Toolkit.getDefaultToolkit().getDesktopProperty("apple.awt.contentScaleFactor");
    if (obj instanceof Float) {
      // 1 = retina not available (regular display). Usually, for retina enabled displays returns 2.
      scaleFactor = ((Float) obj);
    }
   
    return scaleFactor;
  }

 
 
  /**
   * Checks HiDPI support for Java 7 and newer.
   *
   * @return <code>true<code> if the HiDPI feature is enabled.
   */
  private static float getJava7OrLaterContentScaleFactor() {
    float scaleFactor = 1;
 
    GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
    final GraphicsDevice device = env.getDefaultScreenDevice();

    try {
      Field field = device.getClass().getDeclaredField("scale");
      if (field != null) {
        field.setAccessible(true);
        Object scale = field.get(device);
       
        if (scale instanceof Integer) {
          scaleFactor = (Integer) scale;
        }
      }
    } catch (Throwable e) {
      // Ignore     
    }

    return scaleFactor;
  }


So for MAC your predefined "title_buttons.gif" should be saved with a dimension at least double than it is now.
Then you would render them with a custom image icon which actually down scales the image like:

Code: Select all
/**
 * The Retina Icon is designed for the platforms supporting the
 * {@link RetinaType#RETINA_SCALED_GRAPHICS_AND_HIDPI_ICONS}. Currently
 * this type of retina is supported only on Mac OS X.
 *
 * These icons report a size of <code>(w, h)</code> but they store a
 * true image of <code>(w*f, h*f)</code>, where <code>f</code> is the
 * scale factor of the display.
 *
 * @author gabi_ionescu, dan
 */
public class RetinaIcon extends ImageIcon {

  /**
   * Constructor
   *
   * @param image is the true image to be displayed. Double or f-sized.
   * @param displayScalingfactor is the current display scaling factor.
   */
  public RetinaIcon(final Image image, final float displayScalingfactor) {
    super(image);
    this.displayScalingfactor = displayScalingfactor;
  }

  /**
   * The display scaling factor. Mac OS X uses a factor of 2 for its Retina display.
   */
  private float displayScalingfactor = 2.0f;
 
  /**
   * @see javax.swing.ImageIcon#getIconWidth()
   */
  @Override
  public int getIconWidth() {
    return (int) (super.getIconWidth() / displayScalingfactor);
  }

  /**
   * @see javax.swing.ImageIcon#getIconHeight()
   */
  @Override
  public int getIconHeight() {
    return (int) (super.getIconHeight() / displayScalingfactor);
  }

  /**
   * Paints the true image in the specified graphics device but
   * uses a down-scale factor equal to the the display scaling factor.
   * In this way the large image results in a displayed smaller
   * image, but with a higher DPI.
   *
   *
   * @see javax.swing.ImageIcon#paintIcon(java.awt.Component, java.awt.Graphics, int, int)
   */
  @Override
  public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
    ImageObserver observer = getImageObserver();

    if (observer == null) {
      observer = c;
    }
    Image image = getImage();
    int width = image.getWidth(observer);
    int height = image.getHeight(observer);
   
    Graphics graphics = g.create(x, y, width, height);
    if (graphics instanceof Graphics2D) {
      final Graphics2D g2d = (Graphics2D) graphics;
      //Scale the image half it size.
      g2d.scale(1/displayScalingfactor, 1/displayScalingfactor);
      g2d.drawImage(image, 0, 0, observer);
      g2d.dispose();
    }
   
  }

  /**
   * Get the display scaling factor.
   *
   * @return The display scaling factor.
   */
  public float getDisplayScalingFactor() {
    return displayScalingfactor;
  }

}


Regards,
Radu
Radu Coravu
<oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com
Radu
 
Posts: 122
Joined: Fri Jul 22, 2005 5:57 am

Re: Support retina display

Postby JIDE Support » Wed Apr 01, 2015 8:43 am

If you send me the new icons, that'll be great. Thanks.

I will look at the code and try to integrate it. Thanks again.
JIDE Software Technical Support Team
JIDE Support
Site Admin
 
Posts: 37219
Joined: Sun Sep 14, 2003 10:49 am

Re: Support retina display

Postby Radu » Wed Apr 01, 2015 11:08 pm

Hi,

I attached the two newer versions of the buttons our designer has created. You are free to use them for your product.
For supporting Windows High DPI we use JNA to read a key in the registry and use it if Windows 8 is used, something like:

Code: Select all
 
  /**
   * At a 100% scaling, the DPI is 96.
   */
  private static final float WIN_DEFAULT_DPI = 96;

Integer winDPIScaling;
    if (PlatformDetector.isWin7()) {
      winDPIScaling = 1;
    } else {
      // Win 8 or later.
      winDPIScaling = RegistryUtil.getRegistryIntValue(
          RegistryUtil.HKEY_CURRENT_USER,
          "Control Panel\\Desktop",
          "Win8DpiScaling"); 
      if(winDPIScaling == null){
        winDPIScaling = 0;
      }
    }

    Integer desktopDPIOverride;
    if (PlatformDetector.isWin7()) {
      desktopDPIOverride = 0;
    } else {
      // Win 8 or later.
      desktopDPIOverride = RegistryUtil.getRegistryIntValue(
          RegistryUtil.HKEY_CURRENT_USER,
          "Control Panel\\Desktop",
          "DesktopDPIOverride");
      if(desktopDPIOverride == null){
        desktopDPIOverride = 0;
      }

    }
   
   
    if (winDPIScaling == 1 && desktopDPIOverride == 0){
      // There is scaling, but on override (magnifying glass).
      Integer logPixels = RegistryUtil.getRegistryIntValue(
          RegistryUtil.HKEY_CURRENT_USER,
          "Control Panel\\Desktop",
          "LogPixels");
     
      if (logPixels != null && logPixels != WIN_DEFAULT_DPI){     
        this.scalingFactor = ((float)logPixels)/WIN_DEFAULT_DPI;       
      }   
    }


where RegistryUtil uses com.sun.jna.platform.win32.Advapi32Util.

Then we try to map the resolution to an icon scaling factor like 1, 2, 4 or 8:

Code: Select all
 
  /**
   * The scaling factors that can be applied for icons. For the Mac retina
   * display, this factor is 2, and the icon resources contain @x2 in their
   * name. But in the future we might support more than this, for instance 1.5 or 4.
   */
  protected static float ALLOWED_ICON_SCALING_FACTORS[] = new float[] {1, 2};

 /**
   * Get the scaling factor for icons on a HiDPI display.
   *
   * @return Returns the HiDPI scaling factor for the icons. This is
   * relevant on Windows (maybe other platforms), where the application
   * is aware of the HiDPI.
   * On Mac the platform directly scales the graphics.
   * <p> This is different from the one returned by {@link #getScalingFactor()}, because
   * some scaling factors are not good for scaling icon graphics. For instance
   * having a generic 1.2 scaling factor should not be used for the icons. It is better to
   * use 1.0 or 2, or 1.5.
   * <p> The value is one of the ones from {@link #ALLOWED_ICON_SCALING_FACTORS}. 
   */
  public final float getIconScalingFactor() {
    float iconScalingFactor = 1;

    if (isRetina()){   
      int pos = 0;
      float delta = Float.MAX_VALUE;
      for (int i = 0; i < ALLOWED_ICON_SCALING_FACTORS.length; i++) {     
        float nd = scalingFactor - ALLOWED_ICON_SCALING_FACTORS[i];
        if (nd < delta && nd >=0){
          delta = nd;
          pos = i;
        }
      }
 
      iconScalingFactor = ALLOWED_ICON_SCALING_FACTORS[pos];
    }
    return iconScalingFactor;
  }


then we try to create an ImageIcon over the image which is four times larger and scale it down accordingly if we detected a scaling factor of 2.

Regards,
Radu
Attachments
title_buttons_mac_disabled.png
title_buttons_mac_disabled.png (387 Bytes) Viewed 38921 times
title_buttons.png
title_buttons.png (2.12 KiB) Viewed 38921 times
Radu Coravu
<oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com
Radu
 
Posts: 122
Joined: Fri Jul 22, 2005 5:57 am


Return to JIDE Icons Discussion

Who is online

Users browsing this forum: No registered users and 2 guests