From e197195a25a56089f4bd797e40ad04e0ad2c0b6f Mon Sep 17 00:00:00 2001 From: Shahzaib Ibrahim Date: Tue, 17 Sep 2024 16:38:32 +0200 Subject: [PATCH] Drawing custom menu items for Menu Bar When switched to Dark Theme, using gc to draw menu item, moving the 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. --- .../org/eclipse/swt/internal/win32/OS.java | 3 + .../win32/org/eclipse/swt/widgets/Menu.java | 2 +- .../org/eclipse/swt/widgets/MenuItem.java | 76 ++++++++++++------- 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java index c7b704ddcab..bad23442f90 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java @@ -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; @@ -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; diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java index 03f18f19925..b35939ef3d9 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Menu.java @@ -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); diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java index 1105dea32c7..35d240cae6d 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/MenuItem.java @@ -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 = 15; + final static int ADDED_ITEM_WIDTH = 15; static { DPIZoomChangeRegistry.registerHandler(MenuItem::handleDPIChange, MenuItem.class); } @@ -1121,27 +1122,51 @@ 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) { +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); - /* - * Bug in Windows. When a bitmap is included in the - * menu bar, the HDC seems to already include the left - * 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 x = (parent.style & SWT.BAR) == 0 ? MARGIN_WIDTH * 2 : struct.left; 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 (); + 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 bounds = this.getBounds(); + + 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(DPIUtil.scaleDown(x, zoom), DPIUtil.scaleDown(struct.top, zoom), DPIUtil.scaleDown(bounds.width + (image != null ? image.getBounds().width : 0), zoom), DPIUtil.scaleDown(bounds.height, zoom)); + + int xMargin = DPIUtil.scaleDown(x + LEFT_TEXT_MARGIN, zoom) + (this.image != null ? this.image.getBounds().width : 0); + int yMargin = DPIUtil.scaleDown(struct.top + MARGIN_HEIGHT, zoom); + gc.drawText(drawnText, xMargin, yMargin, flags); + } + if (image != null) { + Image image = getEnabled() ? this.image : new Image(display, this.image, SWT.IMAGE_DISABLE); + gc.drawImage(image, DPIUtil.scaleDown(x + LEFT_TEXT_MARGIN, zoom), DPIUtil.scaleDown(struct.top + MARGIN_HEIGHT, 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; } @@ -1151,17 +1176,12 @@ LRESULT wmMeasureChild (long wParam, long lParam) { if ((parent.style & SWT.BAR) != 0) { if (parent.needsMenuCallback()) { - /* - * Weirdness in Windows. Setting `HBMMENU_CALLBACK` causes - * item sizes to mean something else. It seems that it is - * the size of left margin before the text. At the same time, - * 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); + GC gc = new GC (display); + String textWithoutMnemonicCharacter = getText().replace("&", ""); + Point points = gc.textExtent(textWithoutMnemonicCharacter); + gc.dispose (); + struct.itemHeight = DPIUtil.scaleUp(points.y, nativeZoom); + struct.itemWidth = DPIUtil.scaleUp(points.x + ADDED_ITEM_WIDTH, nativeZoom); OS.MoveMemory (lParam, struct, MEASUREITEMSTRUCT.sizeof); return null; }