Skip to content

Commit 84564cf

Browse files
committed
MenuItem Image Scaling with DPI aware metrics #62
This commit contributes to scaling of the MenuItem::hBitmap with the DPI Aware System Metrics for the size of the SM_CYMENUCHECK since the expected size of the Context menu images can differ from the size specific to the zoom level of the monitor. It also corrects the rounding error in the obtained size using the system metrics API due to fractional scaling factor differences making sure the images are painted as per the expected size. contributes to #62 and #127
1 parent 7c818d6 commit 84564cf

File tree

2 files changed

+57
-2
lines changed
  • bundles/org.eclipse.swt
    • Eclipse SWT PI/win32/org/eclipse/swt/internal/win32
    • Eclipse SWT/win32/org/eclipse/swt/widgets

2 files changed

+57
-2
lines changed

bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,7 @@ public class OS extends C {
12481248
public static final int SM_CYFOCUSBORDER = 84;
12491249
public static final int SM_CYHSCROLL = 0x3;
12501250
public static final int SM_CYMENU = 0xf;
1251+
public static final int SM_CYMENUCHECK = 72;
12511252
public static final int SM_CXMINTRACK = 34;
12521253
public static final int SM_CYMINTRACK = 35;
12531254
public static final int SM_CXMAXTRACK = 59;

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -781,8 +781,7 @@ public void setImage (Image image) {
781781
info.hbmpItem = OS.HBMMENU_CALLBACK;
782782
} else {
783783
if (OS.IsAppThemed ()) {
784-
if (hBitmap != 0) OS.DeleteObject (hBitmap);
785-
info.hbmpItem = hBitmap = image != null ? Display.create32bitDIB (image, getZoom()) : 0;
784+
info.hbmpItem = hBitmap = getMenuItemIconBitmapHandle(image);
786785
} else {
787786
info.hbmpItem = image != null ? OS.HBMMENU_CALLBACK : 0;
788787
}
@@ -792,6 +791,61 @@ public void setImage (Image image) {
792791
parent.redraw ();
793792
}
794793

794+
private long getMenuItemIconBitmapHandle(Image image) {
795+
if(image == null) {
796+
return 0;
797+
}
798+
if (hBitmap != 0) OS.DeleteObject (hBitmap);
799+
int desiredSize = getMenuItemImageSize();
800+
int zoom = (int) (((double) desiredSize / image.getBounds().height) * 100);
801+
return Display.create32bitDIB (image, zoom);
802+
}
803+
804+
private int getMenuItemImageSize() {
805+
int size = getSystemMetrics(OS.SM_CYMENUCHECK);
806+
int primaryMonitorZoomAtAppStartUp = getPrimaryMonitorZoomAtStartup();
807+
int currentZoom = getZoom();
808+
/*
809+
* Obtaining the size using SM_CYMENUCHECK can have rounding error as the
810+
* scaling of obtained value also depends internally on the primary monitor zoom
811+
* at startup. i.e. primaryMonitorZoomAtAppStartUp = 100%, sizeAt125% = 18 and
812+
* primaryMonitorZoomAtAppStartUp = 125%, sizeAt125% = 19, where sizeAt125% is
813+
* obtained using <code>getSystemMetrics(OS.SM_CYMENUCHECK)</code>. So, we need
814+
* to correct the value in case there has been a rounding error. The clauses
815+
* below have written after observing the pattern of rounding error with various
816+
* combination of zoom types, i.e. quarter (25s), half (50s), full (100s).
817+
*/
818+
if (isHalfZoom(primaryMonitorZoomAtAppStartUp) && isQuarterZoom(currentZoom)) {
819+
size--;
820+
} else if (isQuarterZoom(primaryMonitorZoomAtAppStartUp)) {
821+
if(isFullZoom(currentZoom)) {
822+
size++;
823+
} else if (isQuarterZoom(currentZoom)) {
824+
size--;
825+
}
826+
}
827+
return size;
828+
}
829+
830+
private boolean isHalfZoom(int zoom) {
831+
return zoom % 50 == 0 && zoom % 100 != 0;
832+
}
833+
834+
private boolean isQuarterZoom(int zoom) {
835+
return zoom % 10 != 0 && zoom % 25 == 0;
836+
}
837+
838+
private boolean isFullZoom(int zoom) {
839+
return zoom % 100 == 0;
840+
}
841+
842+
private int getPrimaryMonitorZoomAtStartup() {
843+
long hDC = OS.GetDC(0);
844+
int dpi = OS.GetDeviceCaps(hDC, OS.LOGPIXELSX);
845+
OS.ReleaseDC(0, hDC);
846+
return DPIUtil.mapDPIToZoom(dpi);
847+
}
848+
795849
/**
796850
* Sets the receiver's pull down menu to the argument.
797851
* Only <code>CASCADE</code> menu items can have a

0 commit comments

Comments
 (0)