Skip to content

Commit

Permalink
When switched to Dark Theme, using gc to draw menu item, moving the
Browse files Browse the repository at this point in the history
responsibility from OS due to wrong scaling of menu bar vertically.

Also changing the text color from a grayish tone to white.
Also when ALT key is pressed mnemonics are underlined and work as a toggle, the behavior which was missing from dark theme previously.
  • Loading branch information
ShahzaibIbrahim committed Oct 9, 2024
1 parent bb0f8dd commit 938c086
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,7 @@ public class OS extends C {
public static final int MFS_CHECKED = 0x8;
public static final int MFS_DISABLED = 0x3;
public static final int MFS_GRAYED = 0x3;
public static final int MFT_OWNERDRAW = 0x100;
public static final int MFT_RADIOCHECK = 0x200;
public static final int MFT_RIGHTJUSTIFY = 0x4000;
public static final int MFT_RIGHTORDER = 0x2000;
Expand Down Expand Up @@ -1019,6 +1020,8 @@ public class OS extends C {
public static final int OBJ_PEN = 0x1;
public static final int OBM_CHECKBOXES = 0x7ff7;
public static final int ODS_SELECTED = 0x1;
public static final int ODS_NOACCEL = 0x0100;
public static final int ODS_INACTIVE = 0x80;
public static final int ODT_MENU = 0x1;
public static final int OIC_BANG = 0x7F03;
public static final int OIC_HAND = 0x7F01;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ void createItem (MenuItem item, int index) {
info.fMask = OS.MIIM_ID | OS.MIIM_TYPE | OS.MIIM_DATA;
info.wID = item.id;
info.dwItemData = item.id;
info.fType = item.widgetStyle ();
info.fType = (style & SWT.BAR) != 0 && needsMenuCallback() ? OS.MFT_OWNERDRAW : item.widgetStyle ();
info.dwTypeData = pszText;
boolean success = OS.InsertMenuItem (handle, index, true, info);
if (pszText != 0) OS.HeapFree (hHeap, 0, pszText);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ public class MenuItem extends Item {
/* Image margin. */
final static int MARGIN_WIDTH = 1;
final static int MARGIN_HEIGHT = 1;

final static int LEFT_TEXT_MARGIN = 5;
final static int IMAGE_TEXT_GAP = 3;
static {
DPIZoomChangeRegistry.registerHandler(MenuItem::handleDPIChange, MenuItem.class);
}
Expand Down Expand Up @@ -1121,10 +1122,32 @@ LRESULT wmCommandChild (long wParam, long lParam) {
return null;
}

LRESULT wmDrawChild (long wParam, long lParam) {
DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT ();
OS.MoveMemory (struct, lParam, DRAWITEMSTRUCT.sizeof);
if (image != null) {
@Override
GC createNewGC(long hDC, GCData data) {
if (getDisplay().isRescalingAtRuntime()) {
return super.createNewGC(hDC, data);
} else {
data.nativeZoom = getMonitorZoom();
return GC.win32_new(hDC, data);
}
}

private int getMonitorZoom() {
return getMenu().getShell().getMonitor().zoom;
}

private int getMenuZoom() {
if (getDisplay().isRescalingAtRuntime()) {
return super.getZoom();
} else {
return DPIUtil.getZoomForAutoscaleProperty(getMonitorZoom());
}
}

LRESULT wmDrawChild(long wParam, long lParam) {
DRAWITEMSTRUCT struct = new DRAWITEMSTRUCT();
OS.MoveMemory(struct, lParam, DRAWITEMSTRUCT.sizeof);
if ((text != null || image != null)) {
GCData data = new GCData();
data.device = display;
GC gc = createNewGC(struct.hDC, data);
Expand All @@ -1134,14 +1157,50 @@ LRESULT wmDrawChild (long wParam, long lParam) {
* coordinate. The fix is to ignore this value when
* the item is in a menu bar.
*/
int x = (parent.style & SWT.BAR) != 0 ? MARGIN_WIDTH * 2 : struct.left;
Image image = getEnabled () ? this.image : new Image (display, this.image, SWT.IMAGE_DISABLE);
int zoom = getZoom();
gc.drawImage (image, DPIUtil.scaleDown(x, zoom), DPIUtil.scaleDown(struct.top + MARGIN_HEIGHT, zoom));
if (this.image != image) image.dispose ();
gc.dispose ();
int x = (parent.style & SWT.BAR) == 0 ? MARGIN_WIDTH * 2 : struct.left;
int zoom = getMenuZoom();
Rectangle menuItemArea = null;
if (text != null) {
this.getParent().redraw();
int flags = SWT.DRAW_DELIMITER;
boolean isInactive = ((struct.itemState & OS.ODS_INACTIVE) != 0);
boolean isSelected = ((struct.itemState & OS.ODS_SELECTED) != 0);
boolean isNoAccel = ((struct.itemState & OS.ODS_NOACCEL) != 0);

String drawnText = "";
if(isNoAccel) {
drawnText = this.text.replace("&", "");
} else {
drawnText = this.text;
flags |= SWT.DRAW_MNEMONIC;
}
Rectangle menuItemBounds = this.getBounds();

int fillMenuWidth = DPIUtil.scaleDown(menuItemBounds.width, zoom);
int fillMenuHeight = DPIUtil.scaleDown(menuItemBounds.height, zoom);
menuItemArea = new Rectangle(DPIUtil.scaleDown(x, zoom), DPIUtil.scaleDown(struct.top, zoom), fillMenuWidth, fillMenuHeight);

gc.setForeground(isInactive ? display.getSystemColor(SWT.COLOR_GRAY) : display.getSystemColor(SWT.COLOR_WHITE));
gc.setBackground(isSelected ? display.getSystemColor(SWT.COLOR_DARK_GRAY) : parent.getBackground());
gc.fillRectangle(menuItemArea);

int xPositionText = LEFT_TEXT_MARGIN + DPIUtil.scaleDown(x, zoom) + (this.image != null ? this.image.getBounds().width + IMAGE_TEXT_GAP : 0);
int yPositionText = DPIUtil.scaleDown(struct.top , zoom);
gc.drawText(drawnText, xPositionText, yPositionText, flags);
}
if (image != null) {
Image image = getEnabled() ? this.image : new Image(display, this.image, SWT.IMAGE_DISABLE);
int gap = (menuItemArea.height - image.getBounds().height)/2;
gc.drawImage(image, LEFT_TEXT_MARGIN + DPIUtil.scaleDown(x, zoom), gap + DPIUtil.scaleDown(struct.top, zoom));
if (this.image != image) {
image.dispose();
}
}
gc.dispose();
}
if (parent.foreground != -1) {
OS.SetTextColor(struct.hDC, parent.foreground);
}
if (parent.foreground != -1) OS.SetTextColor (struct.hDC, parent.foreground);
return null;
}

Expand All @@ -1158,10 +1217,11 @@ LRESULT wmMeasureChild (long wParam, long lParam) {
* if menu item has a mnemonic, it's always drawn at a fixed
* position. I have tested on Win7, Win8.1, Win10 and found
* that value of 5 works well in matching text to mnemonic.
* NOTE: autoScaleUpUsingNativeDPI() is used to avoid problems
* with applications that disable automatic scaling.
*/
struct.itemWidth = DPIUtil.scaleUp(5, nativeZoom);
Point point = calculateRenderedTextSize();
int menuZoom = getDisplay().isRescalingAtRuntime()? super.getZoom(): getMonitorZoom();
struct.itemHeight = DPIUtil.scaleUp(point.y, menuZoom);
struct.itemWidth = DPIUtil.scaleUp(LEFT_TEXT_MARGIN + point.x + (this.image != null ? this.image.getBounds().width + IMAGE_TEXT_GAP : 0), menuZoom);
OS.MoveMemory (lParam, struct, MEASUREITEMSTRUCT.sizeof);
return null;
}
Expand Down Expand Up @@ -1205,6 +1265,34 @@ LRESULT wmMeasureChild (long wParam, long lParam) {
return null;
}

private Point calculateRenderedTextSize() {
GC gc = new GC(this.getMenu().getShell());
String textWithoutMnemonicCharacter = getText().replace("&", "");
Point points = gc.textExtent(textWithoutMnemonicCharacter);
gc.dispose();

if (getDisplay().isRescalingAtRuntime()) {
return points;
} else {
int primaryMonitorZoom = this.getDisplay().getDeviceZoom();
int adjustedPrimaryMonitorZoom = DPIUtil.getZoomForAutoscaleProperty(primaryMonitorZoom);
if (primaryMonitorZoom != adjustedPrimaryMonitorZoom) {
// Windows will use a font matching the native primary monitor zoom for calculating the size in pixels,
// GC will use the native primary monitor zoom to scale down from pixels to points in this scenario
// Therefore we need to make sure adjust the points as if it would have been scaled down by the
// native primary monitor zoom.
// Example:
// Primary monitor on 150% with int200: native zoom 150%, adjusted zoom 100%
// Pixel height of font in this example is 15px
// GC calculated height of 15px, scales down with adjusted zoom of 100% and returns 15pt -> should be 10pt
// this calculation is corrected by the following line
// This is the only place, where the GC needs to use the native zoom to do that, therefore it is fixed only here
points = DPIUtil.scaleDown(DPIUtil.scaleUp(points, adjustedPrimaryMonitorZoom), primaryMonitorZoom);
}
return points;
}
}

private static final class MenuItemToolTip extends ToolTip {

public MenuItemToolTip(Shell parent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,17 @@ public class Snippet373 {
static final ImageFileNameProvider filenameProvider = zoom -> {
String path = null;
switch (zoom) {
case 100:
path = IMAGE_PATH_100;
break;
case 150:
path = IMAGE_PATH_150;
break;
case 200:
path = IMAGE_PATH_200;
break;
default:
path = IMAGE_PATH_100;
path = null;
}
return path;
};
Expand Down Expand Up @@ -113,6 +116,61 @@ public void handleEvent(Event e) {
subItem.setAccelerator(SWT.MOD1 + 'A');
subItem.setImage(eclipse);

fileItem = new MenuItem(bar, SWT.CASCADE);
fileItem.setText("&File");
fileItem.setImage(eclipse);
submenu = new Menu(shell, SWT.DROP_DOWN);
fileItem.setMenu(submenu);
subItem = new MenuItem(submenu, SWT.PUSH);
subItem.addListener(SWT.Selection, e -> System.out.println("Item 1"));
subItem.setText("Select &All\tCtrl+A");
subItem.setAccelerator(SWT.MOD1 + 'A');
subItem.setImage(eclipse);

fileItem = new MenuItem(bar, SWT.CASCADE);
fileItem.setText("&File");
fileItem.setImage(eclipse);
submenu = new Menu(shell, SWT.DROP_DOWN);
fileItem.setMenu(submenu);
subItem = new MenuItem(submenu, SWT.PUSH);
subItem.addListener(SWT.Selection, e -> System.out.println("Item 2"));
subItem.setText("Select &All\tCtrl+A");
subItem.setAccelerator(SWT.MOD1 + 'A');
subItem.setImage(eclipse);

fileItem = new MenuItem(bar, SWT.CASCADE);
fileItem.setText("&File");
fileItem.setImage(eclipse);
submenu = new Menu(shell, SWT.DROP_DOWN);
fileItem.setMenu(submenu);
subItem = new MenuItem(submenu, SWT.PUSH);
subItem.addListener(SWT.Selection, e -> System.out.println("Item 3"));
subItem.setText("Select &All\tCtrl+A");
subItem.setAccelerator(SWT.MOD1 + 'A');
subItem.setImage(eclipse);

fileItem = new MenuItem(bar, SWT.CASCADE);
fileItem.setText("&File");
fileItem.setImage(eclipse);
submenu = new Menu(shell, SWT.DROP_DOWN);
fileItem.setMenu(submenu);
subItem = new MenuItem(submenu, SWT.PUSH);
subItem.addListener(SWT.Selection, e -> System.out.println("Item 4"));
subItem.setText("Select &All\tCtrl+A");
subItem.setAccelerator(SWT.MOD1 + 'A');
subItem.setImage(eclipse);

fileItem = new MenuItem(bar, SWT.CASCADE);
fileItem.setText("&File");
fileItem.setImage(eclipse);
submenu = new Menu(shell, SWT.DROP_DOWN);
fileItem.setMenu(submenu);
subItem = new MenuItem(submenu, SWT.PUSH);
subItem.addListener(SWT.Selection, e -> System.out.println("Item 5"));
subItem.setText("Select &All\tCtrl+A");
subItem.setAccelerator(SWT.MOD1 + 'A');
subItem.setImage(eclipse);

// CTabFolder
CTabFolder folder = new CTabFolder(shell, SWT.BORDER);
for (int i = 0; i < 2; i++) {
Expand Down

0 comments on commit 938c086

Please sign in to comment.