Bug 577129 - [Win11] Button with Arrow style does not display arrows (UP/DOWN/LEFT/RIGHT)
Buttons use arrows from scrollbar.
The problem is that on Win11, default arrow image for scrollbar is empty
because scrollbars no longer show arrows unless pressed/disabled/hovered
with mouse pointer.
Change-Id: I44413614690f92a5111dcf74d345e19667a7c89d
Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/191177
Tested-by: Platform Bot <platform-bot@eclipse.org>
Tested-by: Niraj Modi <niraj.modi@in.ibm.com>
Reviewed-by: Niraj Modi <niraj.modi@in.ibm.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java
index 82516a2..592eaed 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Button.java
@@ -1433,6 +1433,71 @@
return super.wmNotifyChild (hdr, wParam, lParam);
}
+static int getThemeStateId(int style, boolean pressed, boolean enabled) {
+ int direction = style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT);
+
+ /*
+ * Feature in Windows. DrawThemeBackground() does not mirror the drawing.
+ * The fix is switch left to right and right to left.
+ */
+ if ((style & SWT.MIRRORED) != 0) {
+ if (direction == SWT.LEFT) {
+ direction = SWT.RIGHT;
+ } else if (direction == SWT.RIGHT) {
+ direction = SWT.LEFT;
+ }
+ }
+
+ /*
+ * On Win11, scrollbars no longer show arrows by default.
+ * Arrows only show up when hot/disabled/pushed.
+ * The workaround is to use hot image in place of default.
+ */
+ boolean hot = false;
+ if (OS.WIN32_BUILD >= OS.WIN32_BUILD_WIN11_21H2) {
+ if (!pressed && enabled) {
+ hot = true;
+ }
+ }
+
+ if (hot) {
+ switch (direction) {
+ case SWT.UP: return OS.ABS_UPHOT;
+ case SWT.DOWN: return OS.ABS_DOWNHOT;
+ case SWT.LEFT: return OS.ABS_LEFTHOT;
+ case SWT.RIGHT: return OS.ABS_RIGHTHOT;
+ }
+ }
+
+ if (pressed) {
+ switch (direction) {
+ case SWT.UP: return OS.ABS_UPPRESSED;
+ case SWT.DOWN: return OS.ABS_DOWNPRESSED;
+ case SWT.LEFT: return OS.ABS_LEFTPRESSED;
+ case SWT.RIGHT: return OS.ABS_RIGHTPRESSED;
+ }
+ }
+
+ if (!enabled) {
+ switch (direction) {
+ case SWT.UP: return OS.ABS_UPDISABLED;
+ case SWT.DOWN: return OS.ABS_DOWNDISABLED;
+ case SWT.LEFT: return OS.ABS_LEFTDISABLED;
+ case SWT.RIGHT: return OS.ABS_RIGHTDISABLED;
+ }
+ }
+
+ switch (direction) {
+ case SWT.UP: return OS.ABS_UPNORMAL;
+ case SWT.DOWN: return OS.ABS_DOWNNORMAL;
+ case SWT.LEFT: return OS.ABS_LEFTNORMAL;
+ case SWT.RIGHT: return OS.ABS_RIGHTNORMAL;
+ }
+
+ // Have some sane value if all else fails
+ return OS.ABS_LEFTNORMAL;
+}
+
@Override
LRESULT wmDrawChild (long wParam, long lParam) {
if ((style & SWT.ARROW) == 0) return super.wmDrawChild (wParam, lParam);
@@ -1441,29 +1506,9 @@
RECT rect = new RECT ();
OS.SetRect (rect, struct.left, struct.top, struct.right, struct.bottom);
if (OS.IsAppThemed ()) {
- int iStateId = OS.ABS_LEFTNORMAL;
- switch (style & (SWT.UP | SWT.DOWN | SWT.LEFT | SWT.RIGHT)) {
- case SWT.UP: iStateId = OS.ABS_UPNORMAL; break;
- case SWT.DOWN: iStateId = OS.ABS_DOWNNORMAL; break;
- case SWT.LEFT: iStateId = OS.ABS_LEFTNORMAL; break;
- case SWT.RIGHT: iStateId = OS.ABS_RIGHTNORMAL; break;
- }
- /*
- * Feature in Windows. DrawThemeBackground() does not mirror the drawing.
- * The fix is switch left to right and right to left.
- */
- if ((style & SWT.MIRRORED) != 0) {
- if ((style & (SWT.LEFT | SWT.RIGHT)) != 0) {
- iStateId = iStateId == OS.ABS_RIGHTNORMAL ? OS.ABS_LEFTNORMAL : OS.ABS_RIGHTNORMAL;
- }
- }
- /*
- * NOTE: The normal, hot, pressed and disabled state is
- * computed relying on the fact that the increment between
- * the direction states is invariant (always separated by 4).
- */
- if (!getEnabled ()) iStateId += OS.ABS_UPDISABLED - OS.ABS_UPNORMAL;
- if ((struct.itemState & OS.ODS_SELECTED) != 0) iStateId += OS.ABS_UPPRESSED - OS.ABS_UPNORMAL;
+ boolean pressed = ((struct.itemState & OS.ODS_SELECTED) != 0);
+ boolean enabled = getEnabled ();
+ int iStateId = getThemeStateId(style, pressed, enabled);
OS.DrawThemeBackground (display.hScrollBarTheme (), struct.hDC, OS.SBP_ARROWBTN, iStateId, rect, null);
} else {
int uState = OS.DFCS_SCROLLLEFT;
diff --git a/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Bug577129_Win11_NoButtonArrows.java b/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Bug577129_Win11_NoButtonArrows.java
new file mode 100644
index 0000000..1958c3e
--- /dev/null
+++ b/tests/org.eclipse.swt.tests/ManualTests/org/eclipse/swt/tests/manual/Bug577129_Win11_NoButtonArrows.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2022 Syntevo and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Syntevo - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.swt.tests.manual;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+public final class Bug577129_Win11_NoButtonArrows {
+ public static void main(String[] args) {
+ final Display display = new Display();
+ final Shell shell = new Shell(display);
+ shell.setLayout (new GridLayout (1, true));
+
+ Label hint = new Label (shell, 0);
+ hint.setText (
+ "1) Run on Win11 (Win10 is not enough)\n" +
+ "2) Bug 577129: Enabled buttons don't show arrows"
+ );
+
+ Composite composite = new Composite(shell, 0);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ composite.setLayout(new GridLayout (5, true));
+
+ Button button;
+
+ new Label(composite, 0).setText("");
+ new Label(composite, 0).setText("UP");
+ new Label(composite, 0).setText("DOWN");
+ new Label(composite, 0).setText("LEFT");
+ new Label(composite, 0).setText("RIGHT");
+
+ for (int isEnabled = 0; isEnabled < 2; isEnabled++) {
+ if (isEnabled != 0) {
+ new Label(composite, 0).setText("Enabled");
+ } else {
+ new Label(composite, 0).setText("Disabled");
+ }
+
+ button = new Button(composite, SWT.ARROW | SWT.UP);
+ if (isEnabled == 0) {
+ button.setEnabled(false);
+ }
+
+ button = new Button(composite, SWT.ARROW | SWT.DOWN);
+ if (isEnabled == 0) {
+ button.setEnabled(false);
+ }
+
+ button = new Button(composite, SWT.ARROW | SWT.LEFT);
+ if (isEnabled == 0) {
+ button.setEnabled(false);
+ }
+
+ button = new Button(composite, SWT.ARROW | SWT.RIGHT);
+ if (isEnabled == 0) {
+ button.setEnabled(false);
+ }
+ }
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+}